From b0f1b32afb4024662677ef5518ca4b4aaf5fdf8d Mon Sep 17 00:00:00 2001 From: Pawel Jakub Dawidek Date: Wed, 3 Jul 2013 22:01:52 +0000 Subject: [PATCH] MFp4 @229476,229478: Make use of two fields: rfdesc and wfdesc to keep bpf descriptor open for reading only in rfdesc and bpf descriptor open for writing only in wfdesc. In the end they will be used by two different processes. Reviewed by: brooks Sponsored by: The FreeBSD Foundation --- sbin/dhclient/bpf.c | 128 +++++++++++++++++++++++------------------- sbin/dhclient/dhcpd.h | 2 +- 2 files changed, 70 insertions(+), 60 deletions(-) diff --git a/sbin/dhclient/bpf.c b/sbin/dhclient/bpf.c index 93410a8e4c4e..c16e4778f5ba 100644 --- a/sbin/dhclient/bpf.c +++ b/sbin/dhclient/bpf.c @@ -61,15 +61,15 @@ __FBSDID("$FreeBSD$"); * mask. */ int -if_register_bpf(struct interface_info *info) +if_register_bpf(struct interface_info *info, int flags) { char filename[50]; int sock, b; /* Open a BPF device */ - for (b = 0; 1; b++) { + for (b = 0;; b++) { snprintf(filename, sizeof(filename), BPF_FORMAT, b); - sock = open(filename, O_RDWR, 0); + sock = open(filename, flags); if (sock < 0) { if (errno == EBUSY) continue; @@ -87,16 +87,76 @@ if_register_bpf(struct interface_info *info) return (sock); } +/* + * Packet write filter program: + * 'ip and udp and src port bootps and dst port (bootps or bootpc)' + */ +struct bpf_insn dhcp_bpf_wfilter[] = { + BPF_STMT(BPF_LD + BPF_B + BPF_IND, 14), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (IPVERSION << 4) + 5, 0, 12), + + /* Make sure this is an IP packet... */ + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 10), + + /* Make sure it's a UDP packet... */ + BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 8), + + /* Make sure this isn't a fragment... */ + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), + BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 6, 0), /* patched */ + + /* Get the IP header length... */ + BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14), + + /* Make sure it's from the right port... */ + BPF_STMT(BPF_LD + BPF_H + BPF_IND, 14), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 68, 0, 3), + + /* Make sure it is to the right ports ... */ + BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1), + + /* If we passed all the tests, ask for the whole packet. */ + BPF_STMT(BPF_RET+BPF_K, (u_int)-1), + + /* Otherwise, drop it. */ + BPF_STMT(BPF_RET+BPF_K, 0), +}; + +int dhcp_bpf_wfilter_len = sizeof(dhcp_bpf_wfilter) / sizeof(struct bpf_insn); + void if_register_send(struct interface_info *info) { + struct bpf_version v; + struct bpf_program p; int sock, on = 1; - /* - * If we're using the bpf API for sending and receiving, we - * don't need to register this interface twice. - */ - info->wfdesc = info->rfdesc; + /* Open a BPF device and hang it on this interface... */ + info->wfdesc = if_register_bpf(info, O_WRONLY); + + /* Make sure the BPF version is in range... */ + if (ioctl(info->wfdesc, BIOCVERSION, &v) < 0) + error("Can't get BPF version: %m"); + + if (v.bv_major != BPF_MAJOR_VERSION || + v.bv_minor < BPF_MINOR_VERSION) + error("Kernel BPF version out of range - recompile dhcpd!"); + + /* Set up the bpf write filter program structure. */ + p.bf_len = dhcp_bpf_wfilter_len; + p.bf_insns = dhcp_bpf_wfilter; + + if (dhcp_bpf_wfilter[7].k == 0x1fff) + dhcp_bpf_wfilter[7].k = htons(IP_MF|IP_OFFMASK); + + if (ioctl(info->wfdesc, BIOCSETWF, &p) < 0) + error("Can't install write filter program: %m"); + + if (ioctl(info->wfdesc, BIOCLOCK, NULL) < 0) + error("Cannot lock bpf"); /* * Use raw socket for unicast send. @@ -144,46 +204,6 @@ struct bpf_insn dhcp_bpf_filter[] = { int dhcp_bpf_filter_len = sizeof(dhcp_bpf_filter) / sizeof(struct bpf_insn); -/* - * Packet write filter program: - * 'ip and udp and src port bootps and dst port (bootps or bootpc)' - */ -struct bpf_insn dhcp_bpf_wfilter[] = { - BPF_STMT(BPF_LD + BPF_B + BPF_IND, 14), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (IPVERSION << 4) + 5, 0, 12), - - /* Make sure this is an IP packet... */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 10), - - /* Make sure it's a UDP packet... */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 8), - - /* Make sure this isn't a fragment... */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), - BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 6, 0), /* patched */ - - /* Get the IP header length... */ - BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14), - - /* Make sure it's from the right port... */ - BPF_STMT(BPF_LD + BPF_H + BPF_IND, 14), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 68, 0, 3), - - /* Make sure it is to the right ports ... */ - BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1), - - /* If we passed all the tests, ask for the whole packet. */ - BPF_STMT(BPF_RET+BPF_K, (u_int)-1), - - /* Otherwise, drop it. */ - BPF_STMT(BPF_RET+BPF_K, 0), -}; - -int dhcp_bpf_wfilter_len = sizeof(dhcp_bpf_wfilter) / sizeof(struct bpf_insn); - void if_register_receive(struct interface_info *info) { @@ -192,7 +212,7 @@ if_register_receive(struct interface_info *info) int flag = 1, sz; /* Open a BPF device and hang it on this interface... */ - info->rfdesc = if_register_bpf(info); + info->rfdesc = if_register_bpf(info, O_RDONLY); /* Make sure the BPF version is in range... */ if (ioctl(info->rfdesc, BIOCVERSION, &v) < 0) @@ -235,16 +255,6 @@ if_register_receive(struct interface_info *info) if (ioctl(info->rfdesc, BIOCSETF, &p) < 0) error("Can't install packet filter program: %m"); - /* Set up the bpf write filter program structure. */ - p.bf_len = dhcp_bpf_wfilter_len; - p.bf_insns = dhcp_bpf_wfilter; - - if (dhcp_bpf_wfilter[7].k == 0x1fff) - dhcp_bpf_wfilter[7].k = htons(IP_MF|IP_OFFMASK); - - if (ioctl(info->rfdesc, BIOCSETWF, &p) < 0) - error("Can't install write filter program: %m"); - if (ioctl(info->rfdesc, BIOCLOCK, NULL) < 0) error("Cannot lock bpf"); } diff --git a/sbin/dhclient/dhcpd.h b/sbin/dhclient/dhcpd.h index 1d0898d9637d..7747d036c77d 100644 --- a/sbin/dhclient/dhcpd.h +++ b/sbin/dhclient/dhcpd.h @@ -297,7 +297,7 @@ struct hash_table *new_hash_table(int); struct hash_bucket *new_hash_bucket(void); /* bpf.c */ -int if_register_bpf(struct interface_info *); +int if_register_bpf(struct interface_info *, int); void if_register_send(struct interface_info *); void if_register_receive(struct interface_info *); void send_packet(struct interface_info *, struct dhcp_packet *, size_t,