From e4785ca653d0e219926692c229673b2c1b8d6ac4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 3 Feb 2014 18:03:42 +0100 Subject: [PATCH] udhcpc: don't use BPF filter, users report problems (bugs 4598, 6746) Signed-off-by: Denys Vlasenko --- networking/udhcp/dhcpc.c | 93 ++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 47 deletions(-) diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 8dee916d9..ee19f5578 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -976,53 +976,6 @@ static int udhcp_raw_socket(int ifindex) int fd; struct sockaddr_ll sock; - /* - * Comment: - * - * I've selected not to see LL header, so BPF doesn't see it, too. - * The filter may also pass non-IP and non-ARP packets, but we do - * a more complete check when receiving the message in userspace. - * - * and filter shamelessly stolen from: - * - * http://www.flamewarmaster.de/software/dhcpclient/ - * - * There are a few other interesting ideas on that page (look under - * "Motivation"). Use of netlink events is most interesting. Think - * of various network servers listening for events and reconfiguring. - * That would obsolete sending HUP signals and/or make use of restarts. - * - * Copyright: 2006, 2007 Stefan Rompf . - * License: GPL v2. - * - * TODO: make conditional? - */ - static const struct sock_filter filter_instr[] = { - /* load 9th byte (protocol) */ - BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9), - /* jump to L1 if it is IPPROTO_UDP, else to L4 */ - BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6), - /* L1: load halfword from offset 6 (flags and frag offset) */ - BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6), - /* jump to L4 if any bits in frag offset field are set, else to L2 */ - BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0), - /* L2: skip IP header (load index reg with header len) */ - BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), - /* load udp destination port from halfword[header_len + 2] */ - BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2), - /* jump to L3 if udp dport is CLIENT_PORT, else to L4 */ - BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1), - /* L3: accept packet */ - BPF_STMT(BPF_RET|BPF_K, 0xffffffff), - /* L4: discard packet */ - BPF_STMT(BPF_RET|BPF_K, 0), - }; - static const struct sock_fprog filter_prog = { - .len = sizeof(filter_instr) / sizeof(filter_instr[0]), - /* casting const away: */ - .filter = (struct sock_filter *) filter_instr, - }; - log1("Opening raw socket on ifindex %d", ifindex); //log2? fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); @@ -1033,13 +986,59 @@ static int udhcp_raw_socket(int ifindex) sock.sll_ifindex = ifindex; xbind(fd, (struct sockaddr *) &sock, sizeof(sock)); +#if 0 /* Several users reported breakage when BPF filter is used */ if (CLIENT_PORT == 68) { /* Use only if standard port is in use */ + /* + * I've selected not to see LL header, so BPF doesn't see it, too. + * The filter may also pass non-IP and non-ARP packets, but we do + * a more complete check when receiving the message in userspace. + * + * and filter shamelessly stolen from: + * + * http://www.flamewarmaster.de/software/dhcpclient/ + * + * There are a few other interesting ideas on that page (look under + * "Motivation"). Use of netlink events is most interesting. Think + * of various network servers listening for events and reconfiguring. + * That would obsolete sending HUP signals and/or make use of restarts. + * + * Copyright: 2006, 2007 Stefan Rompf . + * License: GPL v2. + * + * TODO: make conditional? + */ + static const struct sock_filter filter_instr[] = { + /* load 9th byte (protocol) */ + BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9), + /* jump to L1 if it is IPPROTO_UDP, else to L4 */ + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6), + /* L1: load halfword from offset 6 (flags and frag offset) */ + BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6), + /* jump to L4 if any bits in frag offset field are set, else to L2 */ + BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0), + /* L2: skip IP header (load index reg with header len) */ + BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), + /* load udp destination port from halfword[header_len + 2] */ + BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2), + /* jump to L3 if udp dport is CLIENT_PORT, else to L4 */ + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1), + /* L3: accept packet */ + BPF_STMT(BPF_RET|BPF_K, 0xffffffff), + /* L4: discard packet */ + BPF_STMT(BPF_RET|BPF_K, 0), + }; + static const struct sock_fprog filter_prog = { + .len = sizeof(filter_instr) / sizeof(filter_instr[0]), + /* casting const away: */ + .filter = (struct sock_filter *) filter_instr, + }; /* Ignoring error (kernel may lack support for this) */ if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, sizeof(filter_prog)) >= 0) log1("Attached filter to raw socket fd"); // log? } +#endif if (setsockopt(fd, SOL_PACKET, PACKET_AUXDATA, &const_int_1, sizeof(int)) < 0