Skip to content

Commit

Permalink
Packet Filter Linux ignore VLAN tagged packets
Browse files Browse the repository at this point in the history
If you define kea dhcp on an untagged interface that also has a tagged
vlan interface on top, it will see both dhcp packets (eth0 and eth0.10).

Linux has a feature for auxiliary data on raw sockets which contains
data about the vlan of the packet received.

Kea should only answer packets without a vlan in the aux data,
since those are the data send to the attached interface.
vlan data are missing on the intended interface eth0.10 but set on eth0
for the same packet.

There was a discussion about this here:

http://kea-users.7364.n8.nabble.com/Kea-users-KEA-DHCP-and-VLANS-td1618.html

Signed-off-by: Sven Auhagen <[email protected]>
  • Loading branch information
svenauhagen committed Sep 18, 2020
1 parent 8a575ad commit 949e441
Showing 1 changed file with 40 additions and 1 deletion.
41 changes: 40 additions & 1 deletion src/lib/dhcp/pkt_filter_lpf.cc
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,15 @@ PktFilterLPF::openSocket(Iface& iface,
<< " on the socket " << sock);
}

int one = 1;
if(setsockopt(sock, SOL_PACKET, PACKET_AUXDATA, &one, sizeof(one)) < 0)
{
close(sock);
close(fallback);
isc_throw(SocketConfigError, "Failed to install packet aux data"
<< " on the socket " << sock);
}

struct sockaddr_ll sa;
memset(&sa, 0, sizeof(sockaddr_ll));
sa.sll_family = AF_PACKET;
Expand Down Expand Up @@ -216,6 +225,19 @@ PktFilterLPF::openSocket(Iface& iface,
Pkt4Ptr
PktFilterLPF::receive(Iface& iface, const SocketInfo& socket_info) {
uint8_t raw_buf[IfaceMgr::RCVBUFSIZE];
unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
struct iovec iov;
struct msghdr msg;
struct cmsghdr *cmsg;
uint16_t tp_vlan_tpid;

iov.iov_base = &raw_buf;
iov.iov_len = sizeof(raw_buf);

msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
// First let's get some data from the fallback socket. The data will be
// discarded but we don't want the socket buffer to bloat. We get the
// packets from the socket in loop but most of the time the loop will
Expand All @@ -237,7 +259,10 @@ PktFilterLPF::receive(Iface& iface, const SocketInfo& socket_info) {

// Now that we finished getting data from the fallback socket, we
// have to get the data from the raw socket too.
int data_len = read(socket_info.sockfd_, raw_buf, sizeof(raw_buf));
int data_len;
do {
data_len = recvmsg(socket_info.sockfd_, &msg, 0);
} while (data_len < 0 && errno == EINTR);
// If negative value is returned by read(), it indicates that an
// error occurred. If returned value is 0, no data was read from the
// socket. In both cases something has gone wrong, because we expect
Expand All @@ -247,6 +272,20 @@ PktFilterLPF::receive(Iface& iface, const SocketInfo& socket_info) {
return Pkt4Ptr();
}

tp_vlan_tpid = 0;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level == SOL_PACKET &&
cmsg->cmsg_type == PACKET_AUXDATA) {
struct tpacket_auxdata *aux = (struct tpacket_auxdata *)CMSG_DATA(cmsg);
tp_vlan_tpid = aux->tp_vlan_tpid;
}
}

// Only server non VLAN/QinQ Traffic
if (tp_vlan_tpid != 0) {
return Pkt4Ptr();
}

InputBuffer buf(raw_buf, data_len);

// @todo: This is awkward way to solve the chicken and egg problem
Expand Down

0 comments on commit 949e441

Please sign in to comment.