Igalia / pflua

Packet filtering in Lua
Other
313 stars 39 forks source link

Suboptimal pfmatch compilation #240

Closed wingo closed 9 years ago

wingo commented 9 years ago

In pfmatch.md, there is the following example:

match {
   not ip => forward
   ip src 1.2.3.4 => incoming_ip(&ip[0])
   ip dst 5.6.7.8 => outgoing_ip(&ip[0])
   otherwise => drop
}

compiling to

local cast = require("ffi").cast
return function(self,P,length)
   if length < 14 then goto L5 end
   do
      if cast("uint16_t*", P+12)[0] ~= 8 then goto L5 end
      if length < 14 then goto L9 end
      do
         if cast("uint16_t*", P+12)[0] ~= 8 then goto L9 end
         if length < 34 then goto L9 end
         if cast("uint32_t*", P+26)[0] ~= 67305985 then goto L9 end
         return self.incoming_ip(P, len, 14)
      end
::L9::
      if length < 14 then goto L17 end
      do
         if cast("uint16_t*", P+12)[0] ~= 8 then goto L17 end
         if length < 34 then goto L17 end
         if cast("uint32_t*", P+30)[0] ~= 134678021 then goto L17 end
         return self.outgoing_ip(P, len, 14)
      end
::L17::
      return self.drop(P, len)
   end
::L5::
   return self.forward(P, len)
end

The "length<14" checks are repeated, needlessly. The <34 checks should be hoisted. The two duplicate checks at offset 12 should also be removed.

wingo commented 9 years ago

Here's what pflua-compile --match (unpushed) shows with PF_VERBOSE:

$ cat /tmp/baz.lua
match {
   not ip => forward
   ip src 1.2.3.4 => incoming_ip
   otherwise => drop
}
$ PF_VERBOSE=1 ./env pflua-compile --match "`cat /tmp/baz.lua`"
{ "true" }
{ "if",
  { "if",
    { "<=",
      { "+",
        { "+",
          0,
          12 },
        2 },
      "len" },
    { "=",
      { "ntohs",
        { "[]",
          { "+",
            0,
            12 },
          2 } },
      2048 },
    { "fail" } },
  { "if",
    { "<=",
      { "+",
        { "+",
          0,
          12 },
        2 },
      "len" },
    { "if",
      { "=",
        { "ntohs",
          { "[]",
            { "+",
              0,
              12 },
            2 } },
        2048 },
      { "if",
        { "<=",
          { "+",
            { "+",
              14,
              19 },
            1 },
          "len" },
        { "if",
          { "<=",
            0,
            { "[]",
              { "+",
                14,
                19 },
              1 } },
          { "if",
            { "<=",
              { "+",
                { "+",
                  14,
                  12 },
                4 },
              "len" },
            { "=",
              { "uint32",
                { "ntohl",
                  { "[]",
                    { "+",
                      14,
                      12 },
                    4 } } },
              16909060 },
            { "fail" } },
          { "false" } },
        { "fail" } },
      { "false" } },
    { "fail" } },
  { "false" } }
{ "if",
  { "if",
    { "<=",
      { "+",
        { "+",
          0,
          12 },
        2 },
      "len" },
    { "=",
      { "ntohs",
        { "[]",
          { "+",
            0,
            12 },
          2 } },
      2048 },
    { "fail" } },
  { "false" },
  { "true" } }
{ "if",
  { "if",
    { ">=",
      "len",
      14 },
    { "=",
      { "[]",
        12,
        2 },
      8 },
    { "false" } },
  { "if",
    { "if",
      { ">=",
        "len",
        14 },
      { "if",
        { "=",
          { "[]",
            12,
            2 },
          8 },
        { "if",
          { ">=",
            "len",
            34 },
          { "=",
            { "[]",
              26,
              4 },
            67305985 },
          { "false" } },
        { "false" } },
      { "false" } },
    { "call",
      "incoming_ip" },
    { "call",
      "drop" } },
  { "call",
    "forward" } }
{}
{ "ssa",
  { "start",
    "L1" },
  { "blocks",
    { "block",
      { "label",
        "L1" },
      { "bindings" },
      { "control",
        { "if",
          { ">=",
            "len",
            14 },
          "L6",
          "L5" } } },
    { "block",
      { "label",
        "L6" },
      { "bindings" },
      { "control",
        { "if",
          { "=",
            { "[]",
              12,
              2 },
            8 },
          "L4",
          "L5" } } },
    { "block",
      { "label",
        "L4" },
      { "bindings" },
      { "control",
        { "if",
          { ">=",
            "len",
            14 },
          "L10",
          "L9" } } },
    { "block",
      { "label",
        "L10" },
      { "bindings" },
      { "control",
        { "if",
          { "=",
            { "[]",
              12,
              2 },
            8 },
          "L12",
          "L9" } } },
    { "block",
      { "label",
        "L12" },
      { "bindings" },
      { "control",
        { "if",
          { ">=",
            "len",
            34 },
          "L14",
          "L9" } } },
    { "block",
      { "label",
        "L14" },
      { "bindings" },
      { "control",
        { "if",
          { "=",
            { "[]",
              26,
              4 },
            67305985 },
          "L8",
          "L9" } } },
    { "block",
      { "label",
        "L8" },
      { "bindings" },
      { "control",
        { "return",
          { "call",
            "incoming_ip" } } } },
    { "block",
      { "label",
        "L9" },
      { "bindings" },
      { "control",
        { "return",
          { "call",
            "drop" } } } },
    { "block",
      { "label",
        "L5" },
      { "bindings" },
      { "control",
        { "return",
          { "call",
            "forward" } } } } } }
local cast = require("ffi").cast
return function(self,P,length)
   if length < 14 then goto L5 end
   do
      if cast("uint16_t*", P+12)[0] ~= 8 then goto L5 end
      if length < 14 then goto L9 end
      do
         if cast("uint16_t*", P+12)[0] ~= 8 then goto L9 end
         if length < 34 then goto L9 end
         if cast("uint32_t*", P+26)[0] ~= 67305985 then goto L9 end
         return self.incoming_ip(P, len)
      end
::L9::
      return self.drop(P, len)
   end
::L5::
   return self.forward(P, len)
end