📄 dhcp-rawnet.c
字号:
icmp_destroy(net->icmp_p); if(net->udp_p) udp_destroy(net->udp_p); if(net->dhcp_p) dhcp_destroy(net->dhcp_p); xfree(net); return;}/* The rawnet up and down routines don't mess with the interface * intentionally. They're meant only to close our packet capturing * and packet writing devices so as to free up system resources. *//* Bring pcap/dnet up and down. * Useful for wait states when * we don't want our packet buffers * to fill up. */void rawnet_down(rawnet_t *net){ if(net->pcap != NULL) { pcap_close(net->pcap); net->pcap = NULL; } if(net->eth != NULL) { eth_close(net->eth); net->eth = NULL; } return;}int rawnet_up(rawnet_t *net){ net->pcap = initialize_pcap_device(net->device, net->mtu, net->pcap_filter, net->promiscuous); if(net->pcap == NULL) { ERROR_MESSAGE("could not initialize pcap on device: %s", net->device); return -1; } if((net->pcap_fd = pcap_fileno(net->pcap)) < 0) { ERROR_MESSAGE("could not get pcap descriptor for: %s: %s", net->device, pcap_geterr(net->pcap)); rawnet_down(net); return -1; } net->eth = eth_open(net->device); if(net->eth == NULL) { ERROR_MESSAGE("could not get ethernet handler on device: %s", net->device); rawnet_down(net); return -1; } return 0;}void reinitialize_rawnet(rawnet_t *net, int promiscuous){ net->promiscuous = promiscuous; rawnet_down(net); rawnet_up(net); return;}/* * rawnet get packet: * we already expect a filter to only allow * the following types of packets: * ARP, UDP, and ICMP. * * Anything else is considered malformed. * */int rawnet_get_packet(rawnet_t *net, struct timeval *tm){ const unsigned char *packet; struct pcap_pkthdr pkthdr; int len; fd_set read_set; int retval; net->type = RAWNET_UNKNOWN; while(1) { FD_ZERO(&read_set); FD_SET(net->pcap_fd, &read_set); retval = select((net->pcap_fd + 1), &read_set, NULL, NULL, tm); if(retval == 0) return RAWNET_TIMEOUT; if(retval < 0) return RAWNET_PCAP_ERROR; packet = pcap_next(net->pcap, &pkthdr); if(packet == NULL) continue; /* BPF may return 1 when there really isn't any packet for us. * is this because we're notified prior to filtering? * pcap only returns NULL on EWOULDBLOCK for bpf -- even though * in debugging I *never* get that errno value :| */ else break; } /* Set timestamp. */#if defined(HAVE_BPF_TIMEVAL) /* This is an ugly hack -- why oh why did OpenBSD insist on * creating its own bpf_timeval struct with unsigned values * as opposed to the common UNIX timeval which has signed values. * * * *sigh* * * There really isn't any clean way around this apart from grabbing * our own timestamp instead of using the bpf one. This is inaccurate * but until OpenBSD fixes their braindamage they'll just have to * deal with the inaccuracy. Anything else would be too damaging * to the other UNIX flavors. */ gettimeofday(&net->tstamp, NULL);#else /* HAVE_BPF_TIMEVAL */ net->tstamp = pkthdr.ts;#endif /* HAVE_BPF_TIMEVAL */ /* Read ethernet header and switch on type. * * Fails if malformed or insufficient length. */ if(eth_read_packet_image(net->ether_p, packet, pkthdr.caplen) < 0) return RAWNET_MALFORMED_PACKET; packet += ETH_HDR_LEN; pkthdr.caplen -= ETH_HDR_LEN; switch (eth_get_type(net->ether_p)) { case ETH_TYPE_ARP: if(arp_read_packet_image(net->arp_p, packet, pkthdr.caplen) < 0) return RAWNET_MALFORMED_PACKET; net->type = RAWNET_ARP; return RAWNET_OK; case ETH_TYPE_IP: if(ip_read_packet_image(net->ip_p, packet, pkthdr.caplen) < 0) return RAWNET_MALFORMED_PACKET; len = ip_get_hl(net->ip_p); packet += len; pkthdr.caplen -= len; switch (ip_get_proto(net->ip_p)) { case IP_PROTO_UDP: if(udp_read_packet_image(net->udp_p, packet, pkthdr.caplen) < 0) return RAWNET_MALFORMED_PACKET; /* We assume any UDP packet does contain a DHCP packet. * So try and grab it here. */ packet += UDP_HDR_LEN; pkthdr.caplen -= UDP_HDR_LEN; /* purge dhcp so we get rid of old options. */ dhcp_purge(net->dhcp_p); if(dhcp_read_packet_image(net->dhcp_p, packet, pkthdr.caplen) < 0) return RAWNET_MALFORMED_PACKET; net->type = RAWNET_DHCP; return RAWNET_OK; case IP_PROTO_ICMP: if(icmp_read_packet_image(net->icmp_p, packet, pkthdr.caplen) < 0) return RAWNET_MALFORMED_PACKET; net->type = RAWNET_ICMP; return RAWNET_OK; default: break; } default: break; } return RAWNET_UNHANDLED;}int rawnet_send_packet(rawnet_t *net){ if(eth_send(net->eth, net->packet_data, net->packet_len) != net->packet_len) { ERROR_MESSAGE("could not write to device: %s : %s", net->device, strerror(errno)); return -1; } return 0;}/* Just update the seconds field. * * FIXME: mod this so that it hooks * into the rest of the framework. * right now it's error prone. */void rawnet_dhcp_update(rawnet_t *net, time_t seconds){ unsigned char *packet; uint16_t secs = htons(seconds); /* FIX ME: we're assuming the ip packet header * has no options. */ packet = (net->packet_data + ETH_HDR_LEN + IP_HDR_LEN + UDP_HDR_LEN); packet += 8; /* to seconds field. */ memcpy(packet, &secs, 2); ip_checksum((net->packet_data + ETH_HDR_LEN), (net->packet_len - ETH_HDR_LEN)); return;}/* * We can ask rawnet to validate for us. * Insert checks here to make sure * the packet is as kosher as christmas * (chicken soup). * */int rawnet_is_valid(rawnet_t *net){ switch (net->type) { case RAWNET_DHCP: if(!dhcp_valid_magic_cookie(net->dhcp_p)) break; else return 1; default: /* todo: we need more validation on other packets. */ break; } return 0;}/* Generic send and wait for reply: * * Calls update() after timeout. * Calls check() on every packet coming in. * */int rawnet_packet_transact(rawnet_t *net, void *arg, void (*update) (void *arg), int (*check) (void *arg), time_t max_timeout){ rtt_t *rtt; int retval; unsigned char send_packet = 1; struct timeval timeout; /* create rtt mechanism. */ rtt = rtt_create(max_timeout); /* We loop here and re-send packets if we timeout, or fail a * check on an incoming packets. */ while(1) { if(send_packet) { send_packet = 0; if(rawnet_send_packet(net) < 0) { rtt_destroy(rtt); ERROR_MESSAGE("could not dispatch packet"); return RAWNET_ERROR; } } if(user_interrupt()) { rtt_destroy(rtt); return RAWNET_USER_INTERRUPT; } timeout = rtt_get_timeout(rtt); retval = rawnet_get_packet(net, &timeout); switch (retval) { case RAWNET_PCAP_ERROR: rtt_destroy(rtt); ERROR_MESSAGE("could not wait for packets on: %s", net->device); return RAWNET_ERROR; case RAWNET_TIMEOUT: rtt_timeout(rtt); if(!rtt_can_retry(rtt)) { rtt_destroy(rtt); return RAWNET_TIMEOUT; } if(update) /* update if needed. only called after timeout. */ update(arg); send_packet = 1; break; case RAWNET_OK: if(!check) /* no check? return 0 anyway (we want * any packet it seems). */ return 0; if(check(arg)) { /* if we have a check * then check packet. */ rtt_destroy(rtt); return RAWNET_OK; /* it's good. let's return. */ } /* otherwise we should just continue. */ break; case RAWNET_UNHANDLED: case RAWNET_MALFORMED_PACKET: break; default: FATAL_MESSAGE ("rawnet: invalid return from rawnet_get_packet() -- this is a bug report it please"); } }}/* return datalink type: use pcap for now since it seems to be * giving us the correct datalink FIXME: find out why dnet is * giving us wierd numbers and send in patch. */int rawnet_get_datalink_type(rawnet_t *net){ if(net->pcap == NULL) { return DLT_NULL; /* we have no datalink. */ } return pcap_datalink(net->pcap);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -