#include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> /* To set non blocking on socket */ #include <sys/socket.h> /* Generic socket calls */ #include <netinet/in.h> #include <arpa/inet.h> #include <sys/ioctl.h> #include <time.h> #include <sys/types.h> #include <signal.h> #include <linux/if_packet.h> #include <linux/if_ether.h> #include <linux/if_arp.h> #include <stdarg.h> #include <errno.h> #include "headers.h" static unsigned char dhopt_buff[500]; /* Pointers for all layer data structures */ struct vlan_eth_hdr *vlan_hg; struct iphdr *iph_g = { 0 }; struct udphdr *uh_g = { 0 }; static struct arp_hdr *arp_hg; static struct icmp_hdr *icmp_hg; static unsigned char *dhopt_pointer_g; /* DHCP packet, option buffer and size of option buffer */ static unsigned char dhcp_packet_send[1518]; static unsigned char dhcp_packet_recv[1518]; static u_int16_t dhcp_hdr_size = sizeof(struct dhcpv4_hdr); static u_int32_t dhopt_size; static struct sockaddr_ll ll = { 0 }; /* Socket address structure */ static int sock_packet; static u_char arp_icmp_packet[1514] = { 0 }; static u_char arp_icmp_reply[1514] = { 0 }; static u_int16_t icmp_len = 0; static int have_set_promisc; static unsigned int lease_time; u_char dmac[ETHER_ADDR_LEN]; static void read_options(int len); static int check_packet(int pkt_type, int len); static int map_all_layer_ptr(int pkt_type); /* * Opens PF_PACKET socket and return error if socket * opens fails */ int open_socket() { sock_packet = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if(sock_packet < 0) return SOCKET_ERR; /* Set link layer parameters */ ll.sll_family = AF_PACKET; ll.sll_protocol = htons(ETH_P_ALL); ll.sll_ifindex = iface; ll.sll_hatype = ARPHRD_ETHER; ll.sll_pkttype = PACKET_OTHERHOST; ll.sll_halen = 6; bind(sock_packet, (struct sockaddr *)&ll, sizeof(struct sockaddr_ll)); return 0; } /* * Sets the promiscous mode on the interface */ static int set_clear_promisc(int op) { struct ifreq ifr; if (!op && !have_set_promisc) return 0; memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, iface_name); if (ioctl(sock_packet, SIOCGIFFLAGS, &ifr)) goto error; if (op) { if ((ifr.ifr_flags & IFF_PROMISC)) { have_set_promisc = 0; return 0; } have_set_promisc = 1; } if (op) ifr.ifr_flags |= IFF_PROMISC; else ifr.ifr_flags &= ~IFF_PROMISC; if (ioctl(sock_packet, SIOCSIFFLAGS, &ifr)) goto error; return 0; error: critical("Error on setting promisc: %m"); } int set_promisc() { return set_clear_promisc(1); } int clear_promisc() { return set_clear_promisc(0); } /* * Get address from the interface */ u_int32_t get_interface_address() { int status; struct ifreq ifr; strcpy(ifr.ifr_name, iface_name); ifr.ifr_addr.sa_family = AF_INET; status = ioctl(sock_packet, SIOCGIFADDR, &ifr); if(status < 0) critical("Error getting interface address: %m"); return ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr; } /* * Sends DHCP packet on the socket. Packet type * is passed as argument. Extended to send ARP and ICMP packets */ int send_packet(int pkt_type) { int ret; switch (pkt_type) { case DHCP_MSGDISCOVER: case DHCP_MSGREQUEST: case DHCP_MSGRELEASE: ret = sendto(sock_packet,\ dhcp_packet_send,\ (l2_hdr_size + l3_hdr_size + l4_hdr_size + dhcp_hdr_size + dhopt_size),\ 0,\ (struct sockaddr *) &ll,\ sizeof(ll)); break; case ARP_SEND: ret = sendto(sock_packet,\ arp_icmp_reply,\ 60,\ 0,\ (struct sockaddr *) &ll,\ sizeof(ll)); break; case ICMP_SEND: ret = sendto(sock_packet,\ arp_icmp_reply,\ (l2_hdr_size + l3_hdr_size + ICMP_H + icmp_len),\ 0,\ (struct sockaddr *) &ll,\ sizeof(ll)); break; default: abort(); } if(ret < 0) critical("Packet send failure: %m"); if(pkt_type == DHCP_MSGDISCOVER) { if (!nagios_flag && !quiet) { printf("DHCP discover sent\t - "); printf("Client MAC : " ETH_F_FMT "\n", ETH_F_ARG(dhmac)); } } else if (pkt_type == DHCP_MSGREQUEST) { if (!nagios_flag && !quiet) { printf("DHCP request sent\t - "); printf("Client MAC : " ETH_F_FMT "\n", ETH_F_ARG(dhmac)); } } else if (pkt_type == DHCP_MSGRELEASE) { if (!nagios_flag && !quiet) { printf("DHCP release sent\t - "); printf("Client MAC : " ETH_F_FMT "\n", ETH_F_ARG(dhmac)); } } return 0; } /* * Receives DHCP packet. Packet type is passed as argument * Extended to recv ARP and ICMP packets */ int recv_packet(int pkt_type) { int ret, retval, chk_pkt_state; socklen_t sock_len; fd_set read_fd; struct timeval tval, *tvp; int timeout_rv, recv_len; unsigned char *recv_buf; tval.tv_sec = 5; tval.tv_usec = 0; tvp = &tval; switch (pkt_type) { case DHCP_MSGOFFER: timeout_rv = DHCP_DISC_RESEND; recv_buf = dhcp_packet_recv; recv_len = sizeof(dhcp_packet_recv); break; case DHCP_MSGACK: timeout_rv = DHCP_REQ_RESEND; recv_buf = dhcp_packet_recv; recv_len = sizeof(dhcp_packet_recv); break; case ARP_ICMP_RCV: tvp = &tval_listen; timeout_rv = LISTEN_TIMEOUT; recv_buf = arp_icmp_packet; recv_len = sizeof(arp_icmp_packet); break; default: abort(); } while(tvp->tv_sec != 0) { FD_ZERO(&read_fd); FD_SET(sock_packet, &read_fd); retval = select(sock_packet + 1, &read_fd, NULL, NULL, tvp); if (retval == 0) return timeout_rv; if (retval < 0) abort(); sock_len = sizeof(ll); ret = recvfrom(sock_packet, recv_buf, recv_len, 0, (struct sockaddr *)&ll, &sock_len); if (ret < 0) return timeout_rv; chk_pkt_state = check_packet(pkt_type, ret); switch (chk_pkt_state) { case DHCP_OFFR_RCVD: case DHCP_ACK_RCVD: case DHCP_NAK_RCVD: case ARP_RCVD: case ICMP_RCVD: return chk_pkt_state; } } return timeout_rv; } /* Debug function - Prints the buffer on HEX format */ int print_buff(u_int8_t *buff, int size) { int tmp; printf("\n---------Buffer data-------\n"); for(tmp = 0; tmp < size; tmp++) { printf("%02X ", buff[tmp]); if((tmp % 16) == 0 && tmp != 0) { printf("\n"); } } printf("\n"); return 0; } /* Reset the DHCP option buffer to zero and dhopt_size to zero */ int reset_dhopt_size() { bzero(dhopt_buff, sizeof(dhopt_buff)); dhopt_size = 0; return 0; } void init_rand() { srand(time(NULL) ^ (getpid() << 16)); } /* * Sets a random DHCP xid */ int set_rand_dhcp_xid() { if(dhcp_xid == 0) dhcp_xid = (rand() % 0xfffffff0) + 1; return 0; } /* * IP checksum function - Calculates the IP checksum */ u_int16_t ipchksum(u_int16_t *buff, int words) { unsigned int sum; int i; sum = 0; for(i = 0;i < words; i++){ sum = sum + *(buff + i); } sum = (sum >> 16) + sum; return (u_int16_t)~sum; } /* * ICMP checksum function - Calculates the ICMP checksum */ u_int16_t icmpchksum(u_int16_t *buff, int words) { unsigned int sum; unsigned int last_word = 0; int i; /* Checksum enhancement for odd packets */ if((icmp_len % 2) == 1) { last_word = *((u_int8_t *)buff + icmp_len + ICMP_H - 1); last_word = (htons(last_word) << 8); sum = 0; for(i = 0;i < words; i++){ sum = sum + *(buff + i); } sum = sum + last_word; sum = (sum >> 16) + sum; return (u_int16_t)~sum; } else { sum = 0; for(i = 0;i < words; i++){ sum = sum + *(buff + i); } sum = (sum >> 16) + sum; return (u_int16_t)~sum; } } /* * TCP/UDP checksum function */ u_int16_t l4_sum(u_int16_t *buff, int words, u_int16_t *srcaddr, u_int16_t *dstaddr, u_int16_t proto, u_int16_t len) { unsigned int sum, last_word = 0; int i; /* Checksum enhancement - Support for odd byte packets */ if((htons(len) % 2) == 1) { last_word = *((u_int8_t *)buff + ntohs(len) - 1); last_word = (htons(last_word) << 8); sum = 0; for(i = 0;i < words; i++){ sum = sum + *(buff + i); } sum = sum + last_word; sum = sum + *(srcaddr) + *(srcaddr + 1) + *(dstaddr) + *(dstaddr + 1) + proto + len; sum = (sum >> 16) + sum; return ~sum; } else { /* Original checksum function */ sum = 0; for(i = 0;i < words; i++){ sum = sum + *(buff + i); } sum = sum + *(srcaddr) + *(srcaddr + 1) + *(dstaddr) + *(dstaddr + 1) + proto + len; sum = (sum >> 16) + sum; return ~sum; } } /* * Builds DHCP option53 on dhopt_buff */ int build_option53(int msg_type) { dhopt_buff[dhopt_size++] = DHCP_MESSAGETYPE; dhopt_buff[dhopt_size++] = 1; dhopt_buff[dhopt_size++] = (unsigned char) msg_type; return 0; } /* * Builds DHCP option50 on dhopt_buff */ int build_option50() { dhopt_buff[dhopt_size++] = DHCP_REQUESTEDIP; dhopt_buff[dhopt_size++] = 4; memcpy(dhopt_buff + dhopt_size, &option50_ip, 4); dhopt_size += 4; return 0; } /* * Builds DHCP option51 on dhopt_buff - DHCP lease time requested */ int build_option51() { u_int32_t msg = htonl(option51_lease_time); dhopt_buff[dhopt_size++] = DHCP_LEASETIME; dhopt_buff[dhopt_size++] = 4; memcpy(dhopt_buff + dhopt_size, &msg, 4); dhopt_size += 4; return 0; } /* * Builds DHCP option54 on dhopt_buff */ int build_option54() { dhopt_buff[dhopt_size++] = DHCP_SERVIDENT; dhopt_buff[dhopt_size++] = 4; memcpy(dhopt_buff + dhopt_size, &server_id, 4); dhopt_size += 4; return 0; } /* * Builds DHCP option55 on dhopt_buff */ int build_option55() { dhopt_buff[dhopt_size++] = DHCP_PARAMREQUEST; dhopt_buff[dhopt_size++] = 4; dhopt_buff[dhopt_size++] = DHCP_SUBNETMASK; dhopt_buff[dhopt_size++] = DHCP_ROUTER; dhopt_buff[dhopt_size++] = DHCP_DOMAINNAME; dhopt_buff[dhopt_size++] = DHCP_DNS; return 0; } /* * Builds DHCP option60 on dhopt_buff */ int build_option60_vci() { dhopt_buff[dhopt_size++] = DHCP_CLASSID; dhopt_buff[dhopt_size++] = (unsigned char) strlen(vci_buff); memcpy(dhopt_buff + dhopt_size, vci_buff, strlen(vci_buff)); dhopt_size += strlen(vci_buff); return 0; } /* * Builds DHCP option 12, hostname, on dhopt_buff */ int build_option12_hostname() { dhopt_buff[dhopt_size++] = DHCP_HOSTNAME; dhopt_buff[dhopt_size++] = (unsigned char) strlen(hostname_buff); memcpy(dhopt_buff + dhopt_size, hostname_buff, strlen(hostname_buff)); dhopt_size += strlen(hostname_buff); return 0; } /* * Builds DHCP option 81, fqdn, on dhopt_buff */ int build_option81_fqdn() { unsigned char flags = 0; if (fqdn_n) flags |= FQDN_N_FLAG; if (fqdn_s) flags |= FQDN_S_FLAG; dhopt_buff[dhopt_size++] = DHCP_FQDN; dhopt_buff[dhopt_size++] = (unsigned char) strlen(fqdn_buff) + 3; dhopt_buff[dhopt_size++] = flags; dhopt_buff[dhopt_size++] = 0; dhopt_buff[dhopt_size++] = 0; memcpy(dhopt_buff + dhopt_size, fqdn_buff, strlen(fqdn_buff)); dhopt_size += strlen(fqdn_buff); return 0; } /* * Builds DHCP end of option on dhopt_buff */ int build_optioneof() { dhopt_buff[dhopt_size++] = 0xff; return 0; } static void vlanize(struct vlan_eth_hdr *vhdr) { if (!vlan) return; vhdr->vlan_len = vhdr->vlan_tpi; vhdr->vlan_tpi = htons(ETHERTYPE_VLAN); vhdr->vlan_priority_c_vid = htons(vlan); } /* * Build DHCP packet. Packet type is passed as argument */ int build_dhpacket(int pkt_type) { u_int32_t dhcp_packet_size = dhcp_hdr_size + dhopt_size; if(!dhcp_release_flag) { u_char dmac_tmp[ETHER_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; memcpy(dmac, dmac_tmp, ETHER_ADDR_LEN); } struct vlan_eth_hdr *vhdr = (struct vlan_eth_hdr *)dhcp_packet_send; memcpy(vhdr->vlan_dhost, dmac, ETHER_ADDR_LEN); memcpy(vhdr->vlan_shost, dhmac, ETHER_ADDR_LEN); vhdr->vlan_tpi = htons(ETHERTYPE_IP); vlanize(vhdr); //print_buff(dhcp_packet_disc, sizeof(struct ethernet_hdr)); if (padding_flag && dhcp_packet_size < MINIMUM_PACKET_SIZE) { memset(dhopt_buff + dhopt_size, 0, MINIMUM_PACKET_SIZE - dhcp_packet_size); dhopt_size += MINIMUM_PACKET_SIZE - dhcp_packet_size; } struct iphdr *iph = (struct iphdr *)(dhcp_packet_send + l2_hdr_size); iph->version = 4; iph->ihl = 5; iph->tos = l3_tos; iph->tot_len = htons(l3_hdr_size + l4_hdr_size + dhcp_hdr_size + dhopt_size); iph->id = 0; iph->frag_off = 0; iph->ttl = 64; iph->protocol = 17; iph->check = 0; // Filled later; switch (pkt_type) { case DHCP_MSGDISCOVER: case DHCP_MSGREQUEST: if (unicast_flag) iph->saddr = unicast_ip_address; else iph->saddr = inet_addr("0.0.0.0"); iph->daddr = inet_addr(server_addr); break; case DHCP_MSGRELEASE: iph->saddr = option50_ip; //inet_addr("0.0.0.0"); iph->daddr = server_id; //inet_addr("255.255.255.255"); break; } iph->check = ipchksum((u_int16_t *)(dhcp_packet_send + l2_hdr_size), iph->ihl << 1); struct udphdr *uh = (struct udphdr *) (dhcp_packet_send + l2_hdr_size + l3_hdr_size); uh->source = htons(port + 1); uh->dest = htons(port); u_int16_t l4_proto = 17; u_int16_t l4_len = (l4_hdr_size + dhcp_hdr_size + dhopt_size); uh->len = htons(l4_len); uh->check = 0; /* UDP checksum will be done after dhcp header*/ struct dhcpv4_hdr *dhpointer = (struct dhcpv4_hdr *)(dhcp_packet_send + l2_hdr_size + l3_hdr_size + l4_hdr_size); dhpointer->dhcp_opcode = DHCP_REQUEST; dhpointer->dhcp_htype = ARPHRD_ETHER; dhpointer->dhcp_hlen = ETHER_ADDR_LEN; dhpointer->dhcp_hopcount = 0; dhpointer->dhcp_xid = htonl(dhcp_xid); dhpointer->dhcp_secs = 0; dhpointer->dhcp_flags = bcast_flag; dhpointer->dhcp_yip = 0; if (unicast_flag) dhpointer->dhcp_cip = unicast_ip_address; else dhpointer->dhcp_cip = 0; switch (pkt_type) { case DHCP_MSGDISCOVER: dhpointer->dhcp_sip = 0; break; case DHCP_MSGRELEASE: dhpointer->dhcp_cip = option50_ip; dhpointer->dhcp_sip = 0; break; case DHCP_MSGREQUEST: dhpointer->dhcp_sip = server_id; break; } dhpointer->dhcp_gip = inet_addr(giaddr); memcpy(dhpointer->dhcp_chaddr, dhmac, ETHER_ADDR_LEN); /*dhpointer->dhcp_sname dhpointer->dhcp_file*/ dhpointer->dhcp_magic = htonl(DHCP_MAGIC); /* DHCP option buffer is copied here to DHCP packet */ u_char *dhopt_pointer = (u_char *)(dhcp_packet_send + l2_hdr_size + l3_hdr_size + l4_hdr_size + dhcp_hdr_size); memcpy(dhopt_pointer, dhopt_buff, dhopt_size); /* UDP checksum is done here */ uh->check = l4_sum((u_int16_t *) (dhcp_packet_send + l2_hdr_size + l3_hdr_size), ((dhcp_hdr_size + dhopt_size + l4_hdr_size) / 2), (u_int16_t *)&iph->saddr, (u_int16_t *)&iph->daddr, htons(l4_proto), htons(l4_len)); return 0; } /* * build packet - Builds ARP reply and ICMP reply packets */ int build_packet(int pkt_type) { bzero(arp_icmp_reply, sizeof(arp_icmp_reply)); if(pkt_type == ARP_SEND) { struct vlan_eth_hdr *vhdr = (struct vlan_eth_hdr *)arp_icmp_reply; memcpy(vhdr->vlan_dhost, vlan_hg->vlan_shost, ETHER_ADDR_LEN); memcpy(vhdr->vlan_shost, dhmac, ETHER_ADDR_LEN); vhdr->vlan_tpi = htons(ETHERTYPE_ARP); vlanize(vhdr); struct arp_hdr *arph = (struct arp_hdr *)(arp_icmp_reply + l2_hdr_size); arph->ar_hrd = htons(ARPHRD_ETHER); arph->ar_pro = htons(ETHERTYPE_IP); arph->ar_hln = ETHER_ADDR_LEN; arph->ar_pln = IP_ADDR_LEN; arph->ar_op = htons(ARPOP_REPLY); u_int32_t ip_addr_tmp; ip_addr_tmp = htonl(ip_address); memcpy(arph->sender_mac, dhmac, ETHER_ADDR_LEN); memcpy(arph->sender_ip, (u_char *)&ip_addr_tmp, IP_ADDR_LEN); memcpy(arph->target_mac, arp_hg->sender_mac, ETHER_ADDR_LEN); memcpy(arph->target_ip, arp_hg->sender_ip, IP_ADDR_LEN); } else if(ICMP_SEND) { struct vlan_eth_hdr *vhdr = (struct vlan_eth_hdr *)arp_icmp_reply; memcpy(vhdr->vlan_dhost, vlan_hg->vlan_shost, ETHER_ADDR_LEN); memcpy(vhdr->vlan_shost, dhmac, ETHER_ADDR_LEN); vhdr->vlan_tpi = htons(ETHERTYPE_IP); vlanize(vhdr); //print_buff(dhcp_packet_request, sizeof(struct ethernet_hdr)); struct iphdr *iph = (struct iphdr *)(arp_icmp_reply + l2_hdr_size); iph->version = 4; iph->ihl = 5; iph->tos = l3_tos; iph->tot_len = 0; /* Filled later */ iph->id = 0; /* (iph_g->id + 5000); */ iph->frag_off = 0; iph->ttl = 128; iph->protocol = 1; iph->check = 0; // Filled later; iph->saddr = htonl(ip_address); iph->daddr = iph_g->saddr; /* iph->daddr = inet_addr("255.255.255.255"); */ struct icmp_hdr *ich = (struct icmp_hdr *)(arp_icmp_reply + l2_hdr_size + l3_hdr_size); ich->icmp_type = ICMP_ECHOREPLY; ich->icmp_code = 0; ich->icmp_sum = 0; ich->id = icmp_hg->id; ich->seq = icmp_hg->seq; icmp_len = (ntohs(iph_g->tot_len) - (iph_g->ihl << 2) - ICMP_H); memcpy((((u_char *)&ich->seq) + 1), (((u_char *)&icmp_hg->seq) +1), (icmp_len + 1)); iph->tot_len = htons((l3_hdr_size + ICMP_H + icmp_len)); iph->check = ipchksum((u_int16_t *)(arp_icmp_reply + l2_hdr_size), iph->ihl << 1); ich->icmp_sum = icmpchksum((u_int16_t *)(arp_icmp_reply + l2_hdr_size + l3_hdr_size), ((icmp_len + ICMP_H) / 2)); } return 0; } /* * Checks whether received packet is DHCP offer/ACK/NACK/ARP/ICMP * and retunrs the received packet type */ static int check_packet(int pkt_type, int len) { int ret; if (len < 40) return UNKNOWN_PACKET; if(pkt_type == DHCP_MSGOFFER || pkt_type == DHCP_MSGACK) { if (map_all_layer_ptr(pkt_type)) return UNKNOWN_PACKET; if (vlan) { if (ntohs(vlan_hg->vlan_priority_c_vid) != vlan || ntohs(vlan_hg->vlan_tpi) != ETHERTYPE_VLAN) return UNKNOWN_PACKET; } if (dhopt_pointer_g > dhcp_packet_recv + len) return UNKNOWN_PACKET; if (iph_g->protocol != 17 || uh_g->source != htons(port) || uh_g->dest != htons(port + 1)) return UNKNOWN_PACKET; if (htonl(dhcph_g->dhcp_xid) != dhcp_xid) return UNKNOWN_PACKET; if(*(dhopt_pointer_g + 2) == DHCP_MSGOFFER) ret = DHCP_OFFR_RCVD; else if(*(dhopt_pointer_g + 2) == DHCP_MSGACK) ret = DHCP_ACK_RCVD; else if(*(dhopt_pointer_g + 2) == DHCP_MSGNACK) ret = DHCP_NAK_RCVD; else return UNKNOWN_PACKET; read_options(len); return ret; } else if(pkt_type == ARP_ICMP_RCV) { if (map_all_layer_ptr(ARP_MAP)) return UNKNOWN_PACKET; if(!vlan && vlan_hg->vlan_tpi != htons(ETHERTYPE_ARP)) goto not_arp; if (vlan && (ntohs(vlan_hg->vlan_priority_c_vid) != vlan || vlan_hg->vlan_len != htons(ETHERTYPE_ARP))) goto not_arp; if ((unsigned char *) arp_hg + sizeof(*arp_hg) > arp_icmp_packet + len) return UNKNOWN_PACKET; if((ntohs(arp_hg->ar_op)) == ARPOP_REQUEST && htonl(ip_address) == arp_hg->target_ip32) { if (!quiet) printf("Arp request received\n"); return ARP_RCVD; } return UNKNOWN_PACKET; not_arp: if (map_all_layer_ptr(ICMP_MAP)) return UNKNOWN_PACKET; if(!vlan && vlan_hg->vlan_tpi != htons(ETHERTYPE_IP)) goto not_icmp; if (vlan && (ntohs(vlan_hg->vlan_priority_c_vid) != vlan || vlan_hg->vlan_len != htons(ETHERTYPE_IP))) goto not_icmp; if ((unsigned char *) icmp_hg + sizeof(*icmp_hg) > arp_icmp_packet + len) return -1; if (iph_g->protocol != 1) goto not_icmp; if(ip_address == ntohl(iph_g->daddr) && icmp_hg->icmp_type == ICMP_ECHO) return ICMP_RCVD; not_icmp: return UNKNOWN_PACKET; } return 0; } /* * Sets the server ip and offerered ip on serv_id, option50_ip * from the DHCP offer packet */ int set_serv_id_opt50() { option50_ip = dhcph_g->dhcp_yip; return 0; } static void read_options(int len) { unsigned char *p = dhopt_pointer_g, *end = dhcp_packet_recv + len; while(*(p) != DHCP_END && p < end) { if ((p + *(p + 1) + 2) > end) break; switch(*(p)) { case DHCP_SERVIDENT: server_id = *(u_int32_t *)(p + 2); break; case DHCP_LEASETIME: lease_time = ntohl(*(u_int32_t *)(p + 2)); break; } p = p + *(p + 1) + 2; } } /* * Prints the DHCP offer/ack info */ int print_dhinfo(int pkt_type) { u_int16_t tmp; unsigned char *p; if(pkt_type == DHCP_MSGOFFER) { printf("\nDHCP offer details\n"); printf("----------------------------------------------------------\n"); printf("DHCP offered IP from server - %s\n", get_ip_str(dhcph_g->dhcp_yip)); printf("Next server IP(Probably TFTP server) - %s\n", get_ip_str(dhcph_g->dhcp_sip)); printf("Boot File Name (Probably used in PXE) - %s\n", dhcph_g->dhcp_file); if(dhcph_g->dhcp_gip) { printf("DHCP Relay agent IP - %s\n", get_ip_str(dhcph_g->dhcp_gip)); } } else if( pkt_type == DHCP_MSGACK) { printf("\nDHCP ack details\n"); printf("----------------------------------------------------------\n"); printf("DHCP offered IP from server - %s\n", get_ip_str(dhcph_g->dhcp_yip)); printf("Next server IP(Probably TFTP server) - %s\n", get_ip_str(dhcph_g->dhcp_sip)); printf("Boot File Name (Probably used in PXE) - %s\n", dhcph_g->dhcp_file); if(dhcph_g->dhcp_gip) { printf("DHCP Relay agent IP - %s\n", get_ip_str(dhcph_g->dhcp_gip)); } } p = dhopt_pointer_g; while(*(p) != DHCP_END) { switch(*(p)) { case DHCP_SERVIDENT: printf("DHCP server - %s\n", get_ip_str(*(u_int32_t *)(p + 2))); break; case DHCP_LEASETIME: printf("Lease time - %d Days %d Hours %d Minutes\n", \ (ntohl(*(u_int32_t *)(p + 2))) / (3600 * 24), \ ((ntohl(*(u_int32_t *)(p + 2))) % (3600 * 24)) / 3600, \ (((ntohl(*(u_int32_t *)(p + 2))) % (3600 * 24)) % 3600) / 60); break; case DHCP_SUBNETMASK: printf("Subnet mask - %s\n", get_ip_str(*(u_int32_t *)(p + 2))); break; case DHCP_ROUTER: for(tmp = 0; tmp < (*(p + 1) / 4); tmp++) { printf("Router/gateway - %s\n", get_ip_str(*(u_int32_t *)(p + 2 + (tmp * 4)))); } break; case DHCP_DNS: for(tmp = 0; tmp < ((*(p + 1)) / 4); tmp++) { printf("DNS server - %s\n", get_ip_str(*(u_int32_t *)(p + 2 + (tmp * 4)))); } break; case DHCP_FQDN: { /* Minus 3 beacause 3 bytes are used to flags, rcode1 and rcode2 */ u_int32_t size = (u_int32_t)*(p + 1) - 3; /* Plus 2 to add string terminator */ u_char fqdn_client_name[size + 1]; /* Plus 5 to reach the beginning of the string */ memcpy(fqdn_client_name, p + 5, size); fqdn_client_name[size] = '\0'; printf("FQDN Client name - %s\n", fqdn_client_name); } } p = p + *(p + 1) + 2; } printf("----------------------------------------------------------\n\n"); return 0; } /* * Function maps all pointers on OFFER/ACK/ARP/ICMP packet */ static int map_all_layer_ptr(int pkt_type) { switch (pkt_type) { case DHCP_MSGOFFER: case DHCP_MSGACK: vlan_hg = (struct vlan_eth_hdr *)dhcp_packet_recv; iph_g = (struct iphdr *)(dhcp_packet_recv + l2_hdr_size); uh_g = (struct udphdr *)(dhcp_packet_recv + l2_hdr_size + l3_hdr_size); dhcph_g = (struct dhcpv4_hdr *)(dhcp_packet_recv + l2_hdr_size + l3_hdr_size + l4_hdr_size); dhopt_pointer_g = (u_int8_t *)(dhcp_packet_recv + l2_hdr_size + l3_hdr_size + l4_hdr_size + sizeof(struct dhcpv4_hdr)); break; case ARP_MAP: vlan_hg = (struct vlan_eth_hdr *)arp_icmp_packet; arp_hg = (struct arp_hdr *)(arp_icmp_packet + l2_hdr_size); break; case ICMP_MAP: vlan_hg = (struct vlan_eth_hdr *)arp_icmp_packet; iph_g = (struct iphdr *)(arp_icmp_packet + l2_hdr_size); icmp_hg = (struct icmp_hdr *)(arp_icmp_packet + l2_hdr_size + l3_hdr_size); break; } return 0; } /* * Logs DHCP info to the log file * This file is used later for DHCP release */ int log_dhinfo() { int dh_file; struct dhcp_status ds; dh_file = open(dhmac_fname, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (dh_file < 0) critical("Error opening file: %m"); memset(&ds, 0, sizeof(ds)); ds.magic = STATUS_MAGIC; memcpy(&ds.client_mac, dhmac, sizeof(ds.client_mac)); if (dhcph_g && vlan_hg) { ds.have_ip = 1; ds.client_ip = dhcph_g->dhcp_yip; ds.server_ip = server_id; memcpy(&ds.server_mac, vlan_hg->vlan_shost, sizeof(ds.server_mac)); time(&ds.acquired_at); ds.lease_time = lease_time; } if (ip_listen_flag) ds.listen_pid = getpid(); if (write(dh_file, &ds, sizeof(ds)) != sizeof(ds)) critical("Error writing to file: %m"); close(dh_file); return 0; } /* * Takes the DHCP info from log file and removes it(unlinks it) * Used for DHCP release */ int get_dhinfo() { int dh_file; struct dhcp_status ds; dh_file = open(dhmac_fname, O_RDONLY); if(dh_file < 0) return errno; if (read(dh_file, &ds, sizeof(ds)) != sizeof(ds)) return errno; memcpy(dhmac, ds.client_mac, sizeof(dhmac)); if (ds.have_ip) { option50_ip = ds.client_ip; server_id = ds.server_ip; memcpy(dmac, ds.server_mac, sizeof(dmac)); if (ds.listen_pid) kill(ds.listen_pid, SIGKILL); /* XXX what about promisc mode? */ option51_lease_time = ds.lease_time; lease_expires_at = ds.acquired_at + ds.lease_time; } close(dh_file); return 0; } char *get_ip_str(u_int32_t ip) { struct in_addr src; src.s_addr = ip; inet_ntop(AF_INET, ((struct sockaddr_in *) &src), ip_str, sizeof(ip_str)); return ip_str; } void critical (const char *fmt, ...) { va_list ap; va_start(ap, fmt); if (nagios_flag) { printf("CRITICAL: "); vprintf(fmt, ap); } else { vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); } exit(2); }