New features:

* Unicast requests.
* Nagios output and exit codes.
* Some bug correction.
remotes/origin/HEAD
rubydhash 12 years ago
parent ddb0ab1539
commit 35bde4ab81

@ -56,6 +56,8 @@ u_int16_t fqdn_n = 0;
u_int16_t fqdn_s = 0;
u_int32_t option51_lease_time = 0;
u_int32_t port = 67;
u_int8_t unicast_flag = 0;
u_int8_t nagios_flag = 0;
u_char *giaddr = "0.0.0.0";
u_char *server_addr = "255.255.255.255";
@ -78,6 +80,7 @@ time_t time_now, time_last;
struct arp_hdr *arp_hg = { 0 };
struct icmp_hdr *icmp_hg = { 0 };
u_int32_t unicast_ip_address = 0;
u_int32_t ip_address;
u_char ip_listen_flag = 0;
struct timeval tval_listen = { 3600, 0 };
@ -89,7 +92,8 @@ u_int16_t icmp_len = 0;
/* Help routine for the command line interface */
void print_help(char *cmd)
{
fprintf(stdout, "Usage: %s [ options ] -m mac_address\n", cmd);
fprintf(stdout, "Usage: %s [ options ]\n", cmd);
fprintf(stdout, " -m mac_address\n");
fprintf(stdout, " -r, --release\t\t\t\t# Releases obtained DHCP IP for corresponding MAC\n");
fprintf(stdout, " -L, --option51-lease_time [ Lease_time ] # Option 51. Requested lease time in secondes\n");
fprintf(stdout, " -I, --option50-ip\t[ IP_address ]\t# Option 50 IP address on DHCP discover\n");
@ -109,9 +113,11 @@ void print_help(char *cmd)
fprintf(stdout, " -p, --padding\t\t\t\t# Add padding to packet to be at least 300 bytes\n");
fprintf(stdout, " -P, --port\t\t[ port ]\t# Use port instead of 67\n");
fprintf(stdout, " -g, --giaddr\t\t[ giaddr ]\t# Use giaddr instead of 0.0.0.0\n");
fprintf(stdout, " -u<ip>, --unicast=<ip>\t\t# Unicast request, IP is optional. If not specified, the interface address will be used. \n");
fprintf(stdout, " -a, --nagios\t\t# Nagios output format. \n");
fprintf(stdout, " -S, --server\t\t[ address ]\t# Use server address instead of 255.255.255.255\n");
fprintf(stdout, " -V, --verbose\t\t\t\t# Prints DHCP offer and ack details\n");
fprintf(stdout, " dhtest version 1.2\n");
fprintf(stdout, " dhtest version 1.3\n");
}
@ -121,7 +127,7 @@ int main(int argc, char *argv[])
if(argc < 3) {
print_help(argv[0]);
exit(1);
exit(2);
}
int option_index = 0;
@ -146,6 +152,8 @@ int main(int argc, char *argv[])
{ "padding", no_argument, 0, 'p'},
{ "port", required_argument, 0, 'P'},
{ "giaddr", required_argument, 0, 'g'},
{ "unicast", optional_argument, 0, 'u'},
{ "nagios", no_argument, 0, 'a'},
{ "server", required_argument, 0, 'S'},
{ "release", no_argument, 0, 'r'},
{ 0, 0, 0, 0 }
@ -153,7 +161,7 @@ int main(int argc, char *argv[])
/*getopt routine to get command line arguments*/
while(get_tmp < argc) {
get_cmd = getopt_long(argc, argv, "m:i:v:t:bfVrpT:P:g:S:I:o:k:L:h:n:s:d:",\
get_cmd = getopt_long(argc, argv, "m:i:v:t:bfVrpansu::T:P:g:S:I:o:k:L:h:d:",\
long_options, &option_index);
if(get_cmd == -1 ) {
break;
@ -165,7 +173,7 @@ int main(int argc, char *argv[])
if(strlen(optarg) > 18) {
fprintf(stdout, "Invalid mac address\n");
exit(1);
exit(2);
}
strcpy(dhmac_fname, optarg);
sscanf((char *)optarg, "%2X:%2X:%2X:%2X:%2X:%2X",
@ -181,7 +189,7 @@ int main(int argc, char *argv[])
iface = if_nametoindex(optarg);
if(iface == 0) {
fprintf(stdout, "Interface doesnot exist\n");
exit(1);
exit(2);
}
strncpy(iface_name, optarg, 29);
break;
@ -190,7 +198,7 @@ int main(int argc, char *argv[])
if(atoi(optarg) < 1 || atoi(optarg) > 4095)
{
fprintf(stdout, "VLAN ID is not valid. Range 1 to 4095\n");
exit(1);
exit(2);
}
vlan = atoi(optarg);
l2_hdr_size = 18;
@ -221,7 +229,7 @@ int main(int argc, char *argv[])
case 't':
if(atoi(optarg) >= 256 || atoi(optarg) < 0) {
fprintf(stdout, "Invalid TOS value\n");
exit(1);
exit(2);
}
l3_tos = atoi(optarg);
break;
@ -237,7 +245,7 @@ int main(int argc, char *argv[])
case 'o':
if(strlen(optarg) > 256) {
fprintf(stdout, "VCI string size should be less than 256\n");
exit(1);
exit(2);
}
vci_flag = 1;
memcpy(vci_buff, optarg, sizeof(vci_buff));
@ -246,7 +254,7 @@ int main(int argc, char *argv[])
case 'h':
if(strlen(optarg) > 256) {
fprintf(stdout, "Hostname string size should be less than 256\n");
exit(1);
exit(2);
}
hostname_flag = 1;
memcpy(hostname_buff, optarg, sizeof(hostname_buff));
@ -255,7 +263,7 @@ int main(int argc, char *argv[])
case 'd':
if(strlen(optarg) > 256) {
fprintf(stdout, "FQDN domain name string size should be less than 256\n");
exit(1);
exit(2);
}
fqdn_flag = 1;
memcpy(fqdn_buff, optarg, sizeof(fqdn_buff));
@ -272,7 +280,7 @@ int main(int argc, char *argv[])
case 'T':
if(atoi(optarg) < 5 || atoi(optarg) > 3600) {
fprintf(stdout, "Invalid timout value. Range 5 to 3600\n");
exit(1);
exit(2);
}
timeout = atoi(optarg);
break;
@ -280,7 +288,7 @@ int main(int argc, char *argv[])
case 'P':
if(atoi(optarg) <=0 || atoi(optarg) > 65535) {
fprintf(stdout, "Invalid portt value. Range 1 to 65535\n");
exit(1);
exit(2);
}
port = atoi(optarg);
break;
@ -305,25 +313,49 @@ int main(int argc, char *argv[])
verbose = 1;
break;
case 'u':
if (optarg) {
struct in_addr out;
if (!inet_aton(optarg, &out)) {
fprintf(stdout, "Invalid unicast IP address.");
exit(2);
}
unicast_ip_address = out.s_addr;
}
unicast_flag = 1;
break;
case 'a':
nagios_flag = 1;
break;
default:
exit(1);
exit(2);
}
get_tmp++;
}
if(!dhmac_flag) {
print_help(argv[0]);
exit(1);
exit(2);
}
/* Opens the PF_PACKET socket */
if(open_socket() < 0) {
fprintf(stdout, "Socket error\n");
exit(1);
if (nagios_flag)
fprintf(stdout, "CRITICAL: Socket error.");
else
fprintf(stdout, "Socket error\n");
exit(2);
}
/* Sets the promiscuous mode */
set_promisc();
if (unicast_flag && !unicast_ip_address) {
unicast_ip_address = get_interface_address();
}
/* Sets a random DHCP xid */
set_rand_dhcp_xid();
@ -334,9 +366,13 @@ int main(int argc, char *argv[])
*/
if(dhcp_release_flag) {
if(get_dhinfo() == ERR_FILE_OPEN) {
fprintf(stdout, "Error on opening DHCP info file\n");
fprintf(stdout, "Release the DHCP IP after acquiring\n");
exit(1);
if (nagios_flag) {
fprintf(stdout, "CRITICAL: Error on opening DHCP info file.");
} else {
fprintf(stdout, "Error on opening DHCP info file\n");
fprintf(stdout, "Release the DHCP IP after acquiring\n");
}
exit(2);
}
build_option53(DHCP_MSGRELEASE); /* Option53 DHCP release */
if(hostname_flag) {
@ -390,15 +426,19 @@ int main(int argc, char *argv[])
if(timeout) {
time_now = time(NULL);
if((time_now - time_last) > timeout) {
if (nagios_flag)
fprintf(stdout, "CRITICAL: Timeout reached: DISCOVER.");
close_socket();
exit(1);
exit(2);
}
}
if(dhcp_offer_state == DHCP_OFFR_RCVD) {
fprintf(stdout, "DHCP offer received\t - ");
if (!nagios_flag)
fprintf(stdout, "DHCP offer received\t - ");
set_serv_id_opt50();
fprintf(stdout, "Offered IP : %s\n", get_ip_str(dhcph_g->dhcp_yip));
if(verbose) {
if (!nagios_flag)
fprintf(stdout, "Offered IP : %s\n", get_ip_str(dhcph_g->dhcp_yip));
if(!nagios_flag && verbose) {
print_dhinfo(DHCP_MSGOFFER);
}
}
@ -432,29 +472,38 @@ int main(int argc, char *argv[])
if(timeout) {
time_now = time(NULL);
if((time_now - time_last) > timeout) {
fprintf(stdout, "Timeout reached. Exiting\n");
if (nagios_flag)
fprintf(stdout, "CRITICAL: Timeout reached: REQUEST.");
else
fprintf(stdout, "Timeout reached. Exiting\n");
close_socket();
exit(1);
}
}
if(dhcp_ack_state == DHCP_ACK_RCVD) {
fprintf(stdout, "DHCP ack received\t - ");
fprintf(stdout, "Acquired IP: %s\n", get_ip_str(dhcph_g->dhcp_yip));
if (nagios_flag) {
fprintf(stdout, "OK: Acquired IP: %s", get_ip_str(dhcph_g->dhcp_yip));
} else {
fprintf(stdout, "DHCP ack received\t - ");
fprintf(stdout, "Acquired IP: %s\n", get_ip_str(dhcph_g->dhcp_yip));
}
/* Logs DHCP IP details to log file. This file is used for DHCP release */
log_dhinfo();
if(verbose) {
if(!nagios_flag && verbose) {
print_dhinfo(DHCP_MSGACK);
}
} else if (dhcp_ack_state == DHCP_NAK_RCVD) {
fprintf(stdout, "DHCP nack received\t - ");
fprintf(stdout, "Client MAC : %02x:%02x:%02x:%02x:%02x:%02x\n", \
if (!nagios_flag) {
fprintf(stdout, "DHCP nack received\t - ");
fprintf(stdout, "Client MAC : %02x:%02x:%02x:%02x:%02x:%02x\n", \
dhmac[0], dhmac[1], dhmac[2], dhmac[3], dhmac[4], dhmac[5]);
}
}
}
/* If IP listen flag is enabled, Listen on obtained for ARP, ICMP protocols */
if(ip_listen_flag) {
if(!nagios_flag && ip_listen_flag) {
fprintf(stdout, "\nListening on %s for ARP and ICMP protocols\n", iface_name);
fprintf(stdout, "IP address: %s, Listen timeout: %d seconds\n", get_ip_str(htonl(ip_address)), listen_timeout);
int arp_icmp_rcv_state = 0;

@ -44,6 +44,8 @@ extern u_int8_t hostname_buff[256];
extern u_int8_t fqdn_buff[256];
extern u_int32_t option51_lease_time;
extern u_int32_t port;
extern u_int8_t unicast_flag;
extern u_int8_t nagios_flag;
extern u_char *giaddr;
extern u_char *server_addr;
@ -66,6 +68,7 @@ extern char ip_str[128];
extern u_int32_t server_id, option50_ip;
extern u_int8_t dhcp_release_flag;
extern u_int32_t unicast_ip_address;
extern u_int32_t ip_address;
extern ip_listen_flag;
extern u_char arp_icmp_packet[1514];
@ -122,8 +125,11 @@ int set_promisc()
ifr.ifr_flags = (IFF_PROMISC | IFF_UP);
status = ioctl(sock_packet, SIOCSIFFLAGS, &ifr);
if(status < 0) {
perror("Error on setting promisc");
exit(1);
if (nagios_flag)
fprintf(stdout, "CRITICAL: Error setting promisc.");
else
perror("Error on setting promisc");
exit(2);
}
}
@ -135,12 +141,40 @@ int clear_promisc()
ifr.ifr_flags = IFF_UP;
status = ioctl(sock_packet, SIOCSIFFLAGS, &ifr);
if(status < 0) {
perror("Error on disabling promisc");
exit(1);
if (nagios_flag)
fprintf(stdout, "CRITICAL: Error on disabling promisc");
else
perror("Error on disabling promisc");
exit(2);
}
return 0;
}
/*
* Get address from the interface
*/
u_int32_t get_interface_address()
{
int status;
struct ifreq ifr;
if(!strlen(iface_name)) {
strcpy(iface_name, "eth0");
}
strcpy(ifr.ifr_name, iface_name);
ifr.ifr_addr.sa_family = AF_INET;
status = ioctl(sock_packet, SIOCGIFADDR, &ifr);
if(status < 0) {
if (nagios_flag)
fprintf(stdout, "CRITICAL: Error getting interface address.");
else
perror("Error getting interface address.");
exit(2);
}
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
@ -186,23 +220,32 @@ int send_packet(int pkt_type)
}
if(ret < 0) {
perror("Paket send failure");
if (nagios_flag)
fprintf(stdout, "CRITICAL: Packet send failure.");
else
perror("Packet send failure");
close(sock_packet);
exit(1);
exit(2);
return PACK_SEND_ERR;
} else {
if(pkt_type == DHCP_MSGDISCOVER) {
fprintf(stdout, "DHCP discover sent\t - ");
fprintf(stdout, "Client MAC : %02x:%02x:%02x:%02x:%02x:%02x\n", \
if (!nagios_flag) {
fprintf(stdout, "DHCP discover sent\t - ");
fprintf(stdout, "Client MAC : %02x:%02x:%02x:%02x:%02x:%02x\n", \
dhmac[0], dhmac[1], dhmac[2], dhmac[3], dhmac[4], dhmac[5]);
}
} else if (pkt_type == DHCP_MSGREQUEST) {
fprintf(stdout, "DHCP request sent\t - ");
fprintf(stdout, "Client MAC : %02x:%02x:%02x:%02x:%02x:%02x\n", \
if (!nagios_flag) {
fprintf(stdout, "DHCP request sent\t - ");
fprintf(stdout, "Client MAC : %02x:%02x:%02x:%02x:%02x:%02x\n", \
dhmac[0], dhmac[1], dhmac[2], dhmac[3], dhmac[4], dhmac[5]);
}
} else if (pkt_type == DHCP_MSGRELEASE) {
fprintf(stdout, "DHCP release sent\t - ");
fprintf(stdout, "Client MAC : %02x:%02x:%02x:%02x:%02x:%02x\n", \
if (!nagios_flag) {
fprintf(stdout, "DHCP release sent\t - ");
fprintf(stdout, "Client MAC : %02x:%02x:%02x:%02x:%02x:%02x\n", \
dhmac[0], dhmac[1], dhmac[2], dhmac[3], dhmac[4], dhmac[5]);
}
}
}
return 0;
@ -632,7 +675,10 @@ int build_dhpacket(int pkt_type)
iph->ttl = 64;
iph->protocol = 17;
iph->check = 0; // Filled later;
iph->saddr = inet_addr("0.0.0.0");
if (unicast_flag)
iph->saddr = unicast_ip_address;
else
iph->saddr = inet_addr("0.0.0.0");
iph->daddr = inet_addr(server_addr);
iph->check = ipchksum((u_int16_t *)(dhcp_packet_disc + l2_hdr_size), iph->ihl << 1);
@ -652,7 +698,10 @@ int build_dhpacket(int pkt_type)
dhpointer->dhcp_xid = htonl(dhcp_xid);
dhpointer->dhcp_secs = 0;
dhpointer->dhcp_flags = bcast_flag;
dhpointer->dhcp_cip = 0;
if (unicast_flag)
dhpointer->dhcp_cip = unicast_ip_address;
else
dhpointer->dhcp_cip = 0;
dhpointer->dhcp_yip = 0;
dhpointer->dhcp_sip = 0;
dhpointer->dhcp_gip = inet_addr(giaddr);
@ -699,7 +748,10 @@ int build_dhpacket(int pkt_type)
iph->ttl = 64;
iph->protocol = 17;
iph->check = 0; // Filled later;
iph->saddr = inet_addr("0.0.0.0");
if (unicast_flag)
iph->saddr = unicast_ip_address;
else
iph->saddr = inet_addr("0.0.0.0");
iph->daddr = inet_addr(server_addr);
iph->check = ipchksum((u_int16_t *)(dhcp_packet_request + l2_hdr_size), iph->ihl << 1);
@ -719,7 +771,10 @@ int build_dhpacket(int pkt_type)
dhpointer->dhcp_xid = htonl(dhcp_xid);
dhpointer->dhcp_secs = 0;
dhpointer->dhcp_flags = bcast_flag;
dhpointer->dhcp_cip = 0;
if (unicast_flag)
dhpointer->dhcp_cip = unicast_ip_address;
else
dhpointer->dhcp_cip = 0;
dhpointer->dhcp_yip = 0;
dhpointer->dhcp_sip = 0;
dhpointer->dhcp_gip = inet_addr(giaddr);
@ -1123,8 +1178,11 @@ int log_dhinfo()
dh_file = fopen(dhmac_fname, "w");
if(dh_file == NULL) {
perror("Error on opening file");
exit(1);
if (nagios_flag)
fprintf(stdout, "CRITICAL: Error on opening file.");
else
perror("Error on opening file.");
exit(2);
}
if(!vlan) {
fprintf(dh_file, "Client_mac: %s\n", dhmac_fname);

@ -40,6 +40,7 @@ int print_dhinfo(int pkt_type); /* Prints DHCP offer & ack informations */
int log_dhinfo(); /* Logs DHCP IP info to log file */
int get_dhinfo(); /* Reads log file for mac, ip, serv_ip info */
char *get_ip_str(u_int32_t ip); /* Convert in_addr to string */
u_int32_t get_interface_address(); /* Return the IP address of the interface. */
int set_serv_id_opt50(); /* Sets the server_ip and option50 ip */
/*

Loading…
Cancel
Save