]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#1117] drop packets with vlan tag
authorRazvan Becheriu <razvan@isc.org>
Fri, 27 Feb 2026 15:43:26 +0000 (17:43 +0200)
committerRazvan Becheriu <razvan@isc.org>
Tue, 3 Mar 2026 08:46:22 +0000 (10:46 +0200)
src/lib/dhcp/pkt_filter_bpf.cc
src/lib/dhcp/pkt_filter_lpf.cc

index a5133c4331c561539db4abf67bcdd5dc729b4269..4d6e8dedf061a101ec4692c74d25a3c3e9ee3e21 100644 (file)
@@ -52,13 +52,13 @@ const unsigned int BPF_LOCAL_LOOPBACK_HEADER_LEN = 4;
 struct bpf_insn ethernet_ip_udp_filter [] = {
     // Make sure this is an IP packet: check the half-word (two bytes)
     // at offset 12 in the packet (the Ethernet packet type).  If it
-    // is, advance to the next instruction.  If not, advance 11
+    // is, advance to the next instruction.  If not, advance 13
     // instructions (which takes execution to the last instruction in
     // the sequence: "drop it").
     // #0
     BPF_STMT(BPF_LD + BPF_H + BPF_ABS, ETHERNET_PACKET_TYPE_OFFSET),
     // #1
-    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 11),
+    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 13),
 
     // Make sure it's a UDP packet.  The IP protocol is at offset
     // 9 in the IP header so, adding the Ethernet packet header size
@@ -67,7 +67,7 @@ struct bpf_insn ethernet_ip_udp_filter [] = {
     BPF_STMT(BPF_LD + BPF_B + BPF_ABS,
              ETHERNET_HEADER_LEN + IP_PROTO_TYPE_OFFSET),
     // #3
-    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 9),
+    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 11),
 
     // Make sure this isn't a fragment by checking that the fragment
     // offset field in the IP header is zero.  This field is the
@@ -77,7 +77,7 @@ struct bpf_insn ethernet_ip_udp_filter [] = {
     // #4
     BPF_STMT(BPF_LD + BPF_H + BPF_ABS, ETHERNET_HEADER_LEN + IP_FLAGS_OFFSET),
     // #5
-    BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 7, 0),
+    BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 9, 0),
 
     // Check the packet's destination address. The program will only
     // allow the packets sent to the broadcast address or unicast
@@ -95,7 +95,7 @@ struct bpf_insn ethernet_ip_udp_filter [] = {
     // If this is not broadcast address, compare it with the unicast
     // address specified for the interface.
     // #8
-    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x00000000, 0, 4),
+    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x00000000, 0, 6),
 
     // Get the IP header length.  This is achieved by the following
     // (special) instruction that, given the offset of the start
@@ -116,14 +116,24 @@ struct bpf_insn ethernet_ip_udp_filter [] = {
     // offset 11 in the program.  If this is changed, openSocket() must be
     // updated.
     // #11
-    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP4_SERVER_PORT, 0, 1),
+    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP4_SERVER_PORT, 0, 3),
 
-    // If we passed all the tests, ask for the whole packet.
+    // Make sure this packet does not contain a vlan tag. The tag is stripped
+    // automatically by the kernel when presented to the vlan interface.
+    // Parent interface should not see this packet.
     // #12
+    BPF_STMT(BPF_LD + BPF_B + BPF_ABS, (u_int)SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT),
+
+    // If this packet contains vlan tag drop the packet.
+    // #13
+    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1),
+
+    // If we passed all the tests, ask for the whole packet.
+    // #14
     BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
 
     // Otherwise, drop it.
-    // #13
+    // #15
     BPF_STMT(BPF_RET + BPF_K, 0),
 };
 
@@ -143,7 +153,7 @@ struct bpf_insn loopback_ip_udp_filter [] = {
     // #0
     BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 0),
     // #1
-    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0xFFFFFFFF, 0, 11),
+    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0xFFFFFFFF, 0, 13),
 
     // Make sure it's a UDP packet.  The IP protocol is at offset
     // 9 in the IP header so, adding the pseudo header size 4 bytes
@@ -152,7 +162,7 @@ struct bpf_insn loopback_ip_udp_filter [] = {
     BPF_STMT(BPF_LD + BPF_B + BPF_ABS,
              BPF_LOCAL_LOOPBACK_HEADER_LEN + IP_PROTO_TYPE_OFFSET),
     // #3
-    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 9),
+    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 11),
 
     // Make sure this isn't a fragment by checking that the fragment
     // offset field in the IP header is zero.  This field is the
@@ -163,7 +173,7 @@ struct bpf_insn loopback_ip_udp_filter [] = {
     BPF_STMT(BPF_LD + BPF_H + BPF_ABS,
              BPF_LOCAL_LOOPBACK_HEADER_LEN + IP_FLAGS_OFFSET),
     // #5
-    BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 7, 0),
+    BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 9, 0),
 
     // Check the packet's destination address. The program will only
     // allow the packets sent to the broadcast address or unicast
@@ -181,7 +191,7 @@ struct bpf_insn loopback_ip_udp_filter [] = {
     // If this is not broadcast address, compare it with the unicast
     // address specified for the interface.
     // #8
-    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x00000000, 0, 4),
+    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x00000000, 0, 6),
 
     // Get the IP header length.  This is achieved by the following
     // (special) instruction that, given the offset of the start
@@ -203,18 +213,27 @@ struct bpf_insn loopback_ip_udp_filter [] = {
     // offset 11 in the program.  If this is changed, openSocket() must be
     // updated.
     // #11
-    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP4_SERVER_PORT, 0, 1),
+    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP4_SERVER_PORT, 0, 3),
 
-    // If we passed all the tests, ask for the whole packet.
+    // Make sure this packet does not contain a vlan tag. The tag is stripped
+    // automatically by the kernel when presented to the vlan interface.
+    // Parent interface should not see this packet.
     // #12
+    BPF_STMT (BPF_LD + BPF_B + BPF_ABS, (u_int)SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT),
+
+    // If this packet contains vlan tag drop the packet.
+    // #13
+    BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1),
+
+    // If we passed all the tests, ask for the whole packet.
+    // #14
     BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
 
     // Otherwise, drop it.
-    // #13
+    // #15
     BPF_STMT(BPF_RET + BPF_K, 0),
 };
 
-
 }
 
 using namespace isc::util;
index 2c6bfc726e52c790efd0a38147ffac0bfa30565c..b120e340da7fc2b7a432c731938747963c0b4075 100644 (file)
@@ -46,13 +46,13 @@ using namespace isc::dhcp;
 struct sock_filter dhcp_sock_filter [] = {
     // Make sure this is an IP packet: check the half-word (two bytes)
     // at offset 12 in the packet (the Ethernet packet type).  If it
-    // is, advance to the next instruction.  If not, advance 11
+    // is, advance to the next instruction.  If not, advance 13
     // instructions (which takes execution to the last instruction in
     // the sequence: "drop it").
     // #0
     BPF_STMT(BPF_LD + BPF_H + BPF_ABS, ETHERNET_PACKET_TYPE_OFFSET),
     // #1
-    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 11),
+    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 13),
 
     // Make sure it's a UDP packet.  The IP protocol is at offset
     // 9 in the IP header so, adding the Ethernet packet header size
@@ -61,7 +61,7 @@ struct sock_filter dhcp_sock_filter [] = {
     BPF_STMT(BPF_LD + BPF_B + BPF_ABS,
              ETHERNET_HEADER_LEN + IP_PROTO_TYPE_OFFSET),
     // #3
-    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 9),
+    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 11),
 
     // Make sure this isn't a fragment by checking that the fragment
     // offset field in the IP header is zero.  This field is the
@@ -71,7 +71,7 @@ struct sock_filter dhcp_sock_filter [] = {
     // #4
     BPF_STMT(BPF_LD + BPF_H + BPF_ABS, ETHERNET_HEADER_LEN + IP_FLAGS_OFFSET),
     // #5
-    BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 7, 0),
+    BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 9, 0),
 
     // Check the packet's destination address. The program will only
     // allow the packets sent to the broadcast address or unicast
@@ -89,7 +89,7 @@ struct sock_filter dhcp_sock_filter [] = {
     // If this is not broadcast address, compare it with the unicast
     // address specified for the interface.
     // #8
-    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x00000000, 0, 4),
+    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x00000000, 0, 6),
 
     // Get the IP header length.  This is achieved by the following
     // (special) instruction that, given the offset of the start
@@ -110,14 +110,24 @@ struct sock_filter dhcp_sock_filter [] = {
     // offset 11 in the program.  If this is changed, openSocket() must be
     // updated.
     // #11
-    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP4_SERVER_PORT, 0, 1),
+    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP4_SERVER_PORT, 0, 3),
 
-    // If we passed all the tests, ask for the whole packet.
+    // Make sure this packet does not contain a vlan tag. The tag is stripped
+    // automatically by the kernel when presented to the vlan interface.
+    // Parent interface should not see this packet.
     // #12
+    BPF_STMT(BPF_LD + BPF_B + BPF_ABS, (u_int)SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT),
+
+    // If this packet contains vlan tag drop the packet.
+    // #13
+    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1),
+
+    // If we passed all the tests, ask for the whole packet.
+    // #14
     BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
 
     // Otherwise, drop it.
-    // #13
+    // #15
     BPF_STMT(BPF_RET + BPF_K, 0),
 };