📄 bpf.c
字号:
/* bpf.c BPF socket interface code, originally contributed by Archie Cobbs. *//* * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * <info@isc.org> * http://www.isc.org/ * * This software was contributed to Internet Systems Consortium * by Archie Cobbs. * * Patches for FDDI support on Digital Unix were written by Bill * Stapleton, and maintained for a while by Mike Meredith before he * managed to get me to integrate them. */#ifndef lintstatic char copyright[] ="$Id: bpf.c,v 1.48.2.6 2004/06/17 20:54:38 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";#endif /* not lint */#include "dhcpd.h"#if defined (USE_BPF_SEND) || defined (USE_BPF_RECEIVE) \ || defined (USE_LPF_RECEIVE)# if defined (USE_LPF_RECEIVE)# include <asm/types.h># include <linux/filter.h># define bpf_insn sock_filter /* Linux: dare to be gratuitously different. */# else# include <sys/ioctl.h># include <sys/uio.h># include <net/bpf.h># if defined (NEED_OSF_PFILT_HACKS)# include <net/pfilt.h># endif# endif#include <netinet/in_systm.h>#include "includes/netinet/ip.h"#include "includes/netinet/udp.h"#include "includes/netinet/if_ether.h"#endif/* Reinitializes the specified interface after an address change. This is not required for packet-filter APIs. */#ifdef USE_BPF_SENDvoid if_reinitialize_send (info) struct interface_info *info;{}#endif#ifdef USE_BPF_RECEIVEvoid if_reinitialize_receive (info) struct interface_info *info;{}#endif/* Called by get_interface_list for each interface that's discovered. Opens a packet filter for each interface and adds it to the select mask. */#if defined (USE_BPF_SEND) || defined (USE_BPF_RECEIVE)int if_register_bpf (info) struct interface_info *info;{ int sock; char filename[50]; int b; /* Open a BPF device */ for (b = 0; 1; b++) { /* %Audit% 31 bytes max. %2004.06.17,Safe% */ sprintf(filename, BPF_FORMAT, b); sock = open (filename, O_RDWR, 0); if (sock < 0) { if (errno == EBUSY) { continue; } else { if (!b) log_fatal ("No bpf devices.%s%s%s", " Please read the README", " section for your operating", " system."); log_fatal ("Can't find free bpf: %m"); } } else { break; } } /* Set the BPF device to point at this interface. */ if (ioctl (sock, BIOCSETIF, info -> ifp) < 0) log_fatal ("Can't attach interface %s to bpf device %s: %m", info -> name, filename); return sock;}#endif /* USE_BPF_SEND || USE_BPF_RECEIVE */#ifdef USE_BPF_SENDvoid if_register_send (info) struct interface_info *info;{ /* If we're using the bpf API for sending and receiving, we don't need to register this interface twice. */#ifndef USE_BPF_RECEIVE info -> wfdesc = if_register_bpf (info, interface);#else info -> wfdesc = info -> rfdesc;#endif if (!quiet_interface_discovery) log_info ("Sending on BPF/%s/%s%s%s", info -> name, print_hw_addr (info -> hw_address.hbuf [0], info -> hw_address.hlen - 1, &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : ""));}void if_deregister_send (info) struct interface_info *info;{ /* If we're using the bpf API for sending and receiving, we don't need to register this interface twice. */#ifndef USE_BPF_RECEIVE close (info -> wfdesc);#endif info -> wfdesc = -1; if (!quiet_interface_discovery) log_info ("Disabling output on BPF/%s/%s%s%s", info -> name, print_hw_addr (info -> hw_address.hbuf [0], info -> hw_address.hlen - 1, &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : ""));}#endif /* USE_BPF_SEND */#if defined (USE_BPF_RECEIVE) || defined (USE_LPF_RECEIVE)/* Packet filter program... XXX Changes to the filter program may require changes to the constant offsets used in if_register_send to patch the BPF program! XXX */struct bpf_insn dhcp_bpf_filter [] = { /* 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, 8), /* 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, 6), /* 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, 4, 0), /* Get the IP header length... */ BPF_STMT (BPF_LDX + BPF_B + BPF_MSH, 14), /* Make sure it's to the right port... */ BPF_STMT (BPF_LD + BPF_H + BPF_IND, 16), BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1), /* patch */ /* 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),};#if defined (DEC_FDDI)struct bpf_insn *bpf_fddi_filter;#endifint dhcp_bpf_filter_len = sizeof dhcp_bpf_filter / sizeof (struct bpf_insn);#if defined (HAVE_TR_SUPPORT)struct bpf_insn dhcp_bpf_tr_filter [] = { /* accept all token ring packets due to variable length header */ /* if we want to get clever, insert the program here */ /* 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_tr_filter_len = (sizeof dhcp_bpf_tr_filter / sizeof (struct bpf_insn));#endif /* HAVE_TR_SUPPORT */#endif /* USE_LPF_RECEIVE || USE_BPF_RECEIVE */#if defined (USE_BPF_RECEIVE)void if_register_receive (info) struct interface_info *info;{ int flag = 1; struct bpf_version v; u_int32_t addr; struct bpf_program p; u_int32_t bits;#ifdef DEC_FDDI int link_layer;#endif /* DEC_FDDI */ /* Open a BPF device and hang it on this interface... */ info -> rfdesc = if_register_bpf (info); /* Make sure the BPF version is in range... */ if (ioctl (info -> rfdesc, BIOCVERSION, &v) < 0) log_fatal ("Can't get BPF version: %m"); if (v.bv_major != BPF_MAJOR_VERSION || v.bv_minor < BPF_MINOR_VERSION) log_fatal ("BPF version mismatch - recompile DHCP!"); /* Set immediate mode so that reads return as soon as a packet comes in, rather than waiting for the input buffer to fill with packets. */ if (ioctl (info -> rfdesc, BIOCIMMEDIATE, &flag) < 0) log_fatal ("Can't set immediate mode on bpf device: %m");#ifdef NEED_OSF_PFILT_HACKS /* Allow the copyall flag to be set... */ if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0) log_fatal ("Can't set ALLOWCOPYALL: %m"); /* Clear all the packet filter mode bits first... */ bits = 0; if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0) log_fatal ("Can't clear pfilt bits: %m"); /* Set the ENBATCH, ENCOPYALL, ENBPFHDR bits... */ bits = ENBATCH | ENCOPYALL | ENBPFHDR; if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0) log_fatal ("Can't set ENBATCH|ENCOPYALL|ENBPFHDR: %m");#endif /* Get the required BPF buffer length from the kernel. */ if (ioctl (info -> rfdesc, BIOCGBLEN, &info -> rbuf_max) < 0) log_fatal ("Can't get bpf buffer length: %m"); info -> rbuf = dmalloc (info -> rbuf_max, MDL); if (!info -> rbuf) log_fatal ("Can't allocate %ld bytes for bpf input buffer.", (long)(info -> rbuf_max)); info -> rbuf_offset = 0; info -> rbuf_len = 0; /* Set up the bpf filter program structure. */ p.bf_len = dhcp_bpf_filter_len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -