Skip to content

Commit e26caa3

Browse files
committed
Packet Filter Linux ignore VLAN tagged packets
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]>
1 parent 8a575ad commit e26caa3

File tree

1 file changed

+39
-1
lines changed

1 file changed

+39
-1
lines changed

src/lib/dhcp/pkt_filter_lpf.cc

+39-1
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,15 @@ PktFilterLPF::openSocket(Iface& iface,
180180
<< " on the socket " << sock);
181181
}
182182

183+
int one = 1;
184+
if(setsockopt(sock, SOL_PACKET, PACKET_AUXDATA, &one, sizeof(one)) < 0)
185+
{
186+
close(sock);
187+
close(fallback);
188+
isc_throw(SocketConfigError, "Failed to install packet aux data"
189+
<< " on the socket " << sock);
190+
}
191+
183192
struct sockaddr_ll sa;
184193
memset(&sa, 0, sizeof(sockaddr_ll));
185194
sa.sll_family = AF_PACKET;
@@ -216,6 +225,19 @@ PktFilterLPF::openSocket(Iface& iface,
216225
Pkt4Ptr
217226
PktFilterLPF::receive(Iface& iface, const SocketInfo& socket_info) {
218227
uint8_t raw_buf[IfaceMgr::RCVBUFSIZE];
228+
unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
229+
struct iovec iov;
230+
struct msghdr msg;
231+
struct cmsghdr *cmsg;
232+
uint16_t tp_vlan_tpid;
233+
234+
iov.iov_base = &raw_buf;
235+
iov.iov_len = sizeof(raw_buf);
236+
237+
msg.msg_iov = &iov;
238+
msg.msg_iovlen = 1;
239+
msg.msg_control = cmsgbuf;
240+
msg.msg_controllen = sizeof(cmsgbuf);
219241
// First let's get some data from the fallback socket. The data will be
220242
// discarded but we don't want the socket buffer to bloat. We get the
221243
// packets from the socket in loop but most of the time the loop will
@@ -237,7 +259,9 @@ PktFilterLPF::receive(Iface& iface, const SocketInfo& socket_info) {
237259

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

274+
tp_vlan_tpid = 0;
275+
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
276+
if (cmsg->cmsg_level == SOL_PACKET &&
277+
cmsg->cmsg_type == PACKET_AUXDATA) {
278+
struct tpacket_auxdata *aux = (struct tpacket_auxdata *)CMSG_DATA(cmsg);
279+
tp_vlan_tpid = aux->tp_vlan_tpid;
280+
}
281+
}
282+
283+
// Only server non VLAN/QinQ Traffic
284+
if (tp_vlan_tpid != 0) {
285+
return Pkt4Ptr();
286+
}
287+
250288
InputBuffer buf(raw_buf, data_len);
251289

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

0 commit comments

Comments
 (0)