diff --git a/Targets/Bonito2edev/conf/Bonito b/Targets/Bonito2edev/conf/Bonito index e21210f8..7a3faed3 100644 --- a/Targets/Bonito2edev/conf/Bonito +++ b/Targets/Bonito2edev/conf/Bonito @@ -160,4 +160,6 @@ option IDECD #option HAVE_NB_SERIAL option USE_ENVMAC #option LOOKLIKE_PC +#select cmd_lwdhcp +#select cmd_bootp diff --git a/conf/files b/conf/files index a5cae7f0..4830dd82 100644 --- a/conf/files +++ b/conf/files @@ -115,6 +115,11 @@ pseudo-device crypto: ifnet # Tweak! +file pmon/cmds/lwdhcp/options.c cmd_lwdhcp needs-flag +file pmon/cmds/lwdhcp/packet.c cmd_lwdhcp needs-flag +file pmon/cmds/lwdhcp/lwdhcp.c cmd_lwdhcp needs-flag +file pmon/cmds/cmd_bootp.c cmd_bootp + file net/if_bridge.c bridge needs-count file net/bpf.c bpfilter needs-count diff --git a/pmon/cmds/lwdhcp/Makefile b/pmon/cmds/lwdhcp/Makefile new file mode 100644 index 00000000..1fbbcfb0 --- /dev/null +++ b/pmon/cmds/lwdhcp/Makefile @@ -0,0 +1,18 @@ + +all: lwdhcp + +lwdhcp: lwdhcp.o packet.o options.o + cc -o lwdhcp packet.o options.o lwdhcp.o + +lwdhcp.o: lwdhcp.c lwdhcp.h + cc -c lwdhcp.c + +packet.o: packet.c lwdhcp.h packet.h + cc -c packet.c + +options.o: options.c options.h + cc -c options.c + +clean: + -rm -f lwdhcp *.o + diff --git a/pmon/cmds/lwdhcp/lwdhcp.c b/pmon/cmds/lwdhcp/lwdhcp.c new file mode 100644 index 00000000..59f28b6c --- /dev/null +++ b/pmon/cmds/lwdhcp/lwdhcp.c @@ -0,0 +1,362 @@ +///////////////////////////////////////////////////////////////////////////////////////////////////// +// // +// Light weight DHCP client // +// // +///////////////////////////////////////////////////////////////////////////////////////////////////// + + +#include +#include +#include +#include + +#ifdef PMON + #ifdef KERNEL + #undef KERNEL + #include + #include + #include + #else + #include + #include + #include + #endif + + #define KERNEL + #include + #include + #include +#else + #include + #include + #include + #include + #include +#endif + +#include +#include +#include + +#include "lwdhcp.h" +#include "packet.h" +#include "options.h" + +struct client_config_t client_config; +int dhcp_request; +int fd = 0; +sig_t pre_handler = 0; + +static jmp_buf jmpb; + +static void terminate() +{ + DbgPrint("Program terminated by user.\n"); + dhcp_request = 0; + + if(fd > 0) + close(fd); + + longjmp(jmpb, 1); +} + +static void init() +{ + memset((void *)&client_config, 0, sizeof(struct client_config_t)); + + strcpy(client_config.interface, "rtl0"); + + pre_handler = signal(SIGINT, (sig_t)terminate); +} + +int listen_socket() +{ + int sock, n; + int flag; + int dwValue; + struct ifreq ifr; + struct sockaddr_in clnt; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if(sock < 0) + { + PERROR("socket create error"); + return sock; + } + + bzero((char*)&clnt, sizeof(clnt)); + clnt.sin_family = AF_INET; + clnt.sin_port = htons(CLIENT_PORT); + clnt.sin_addr.s_addr = INADDR_ANY; + + if (bind (sock, (struct sockaddr *)&clnt, sizeof(struct sockaddr_in)) < 0) { + PERROR ("bind failed"); + close (sock); + return -1; + } + + flag = 1; + setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char*)&flag, sizeof(flag)); + + n = 1; + setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&n, sizeof(n)); + + return sock; +} + + +int read_interface(char *interface, int *ifindex, uint32_t *addr, uint8_t *arp) +{ + int fd; + struct ifreq ifr; + struct sockaddr_in *our_ip; + + memset(&ifr, 0, sizeof(struct ifreq)); + if((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) >= 0) + { + ifr.ifr_addr.sa_family = AF_INET; + + strncpy(ifr.ifr_name, interface, IFNAMSIZ-1); + + if (addr) + { + if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) + { + our_ip = (struct sockaddr_in *) &ifr.ifr_addr; + *addr = our_ip->sin_addr.s_addr; + DbgPrint("%s (our ip) = %s\n", ifr.ifr_name, inet_ntoa(our_ip->sin_addr)); + } else + { + PERROR("SIOCGIFADDR failed, is the interface up and configured?\n"); + close(fd); + return -1; + } + } + + //the following code needs to change the PMON source code pmon/pmon/netio/bootp.c line 101 + //int + //getethaddr (unsigned char *eaddr, char *ifc) + //{ + // struct ifnet *ifp; + // struct ifaddr *ifa; + // ...... +#ifndef PMON + if(ioctl(fd, SIOCGIFINDEX, &ifr) == 0) + { + DbgPrint("adapter index %d\n", ifr.ifr_ifindex); + *ifindex = ifr.ifr_ifindex; + } else + { + PERROR("SIOCGIFINDEX failed!\n"); + close(fd); + return -1; + } +#endif + +#ifndef PMON + if (ioctl(fd, SIOCGIFHWADDR, &ifr) == 0) + { + memcpy(arp, ifr.ifr_hwaddr.sa_data, 6); +#else + if(getethaddr(arp, client_config.interface) >= 0) + { +#endif + DbgPrint("adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x\n", + arp[0], arp[1], arp[2], arp[3], arp[4], arp[5]); + } + else{ + PERROR("SIOCGIFHWADDR failed!\n"); + close(fd); + return -1; + } + } + else { + PERROR("socket failed!\n"); + return -1; + } + close(fd); + return 0; +} + + +int lwdhcp(int argc, char* argv[]) +{ + int xid; + fd_set fs; + int ret, totimes; + char buf[1500]; + struct sockaddr_in from; + int size = sizeof(from); + struct dhcp_packet* p; + uint8_t* dhcp_message_type; + struct timeval tv; + + if(getuid()) + { + DbgPrint("Only root can run this program!\n"); + return 0; + } + + DbgPrint("Light weight DHCP client starts...\n"); + init(); + + if(setjmp(jmpb)) + { + signal(SIGINT, pre_handler); + sigsetmask(0); + return 0; + } + + + if(read_interface(client_config.interface, &client_config.ifindex, + &client_config.addr, client_config.arp) < 0) + { + DbgPrint("read_interface error"); + return 0; + } + + if((fd = listen_socket()) < 0) + { + return 0; + } + + //srand(time(NULL)); + //xid = rand(); + totimes = 3; + +tryagain: + if(send_discover(xid) < 0) + if(--totimes > 0) + goto tryagain; + else + { + DbgPrint("Fail to send DHCPDISCOVER...\n"); + return 0; + } + + FD_ZERO(&fs); + FD_SET(fd, &fs); + tv.tv_sec = 3; + tv.tv_usec = 0; + //receiving DHCPOFFER + while(1) + { + dhcp_request = 1; + ret = select(fd + 1, &fs, NULL, NULL, &tv); + + if(ret == -1) + PERROR("select error"); + else if(ret == 0) + { + if(--totimes > 0) + goto tryagain; + else + { + dhcp_request = 0; + DbgPrint("Fail to get IP from DHCP server, it seems that there is no DHCP server.\n"); + close(fd); + return 0; + } + } + + size = sizeof(from); + if(recvfrom(fd, buf, sizeof(struct dhcp_packet), (struct sockaddr *)0, &from, &size) < 0) + continue; + + dhcp_request = 0; + + p = (struct dhcp_packet *)buf; + + if(p->xid != xid) + continue; + + dhcp_message_type = get_dhcp_option(p, DHCP_MESSAGE_TYPE); + if(!dhcp_message_type) + continue; + else if(*dhcp_message_type != DHCPOFFER) + continue; + + DbgPrint("DHCPOFFER received...\n"); + break; + } + + //sending DHCPREQUEST + send_request(xid, *((uint32_t*)(&(p->siaddr))), *((uint32_t*)(&p->yiaddr))); + + tv.tv_sec = 3; + tv.tv_usec = 0; + //receiving DHCPACK + while(1) + { + dhcp_request = 1; + ret = select(fd + 1, &fs, NULL, NULL, &tv); + + if(ret == -1) + PERROR("select error"); + else if(ret == 0) + { + if(--totimes > 0) + goto tryagain; + else + { + dhcp_request = 0; + DbgPrint("Fail to get IP from DHCP server, no ACK from DHCP server.\n"); + close(fd); + return 0; + } + } + + //get_raw_packet(buf, fd); + + size = sizeof(struct sockaddr); + recvfrom(fd, buf, sizeof(struct dhcp_packet), 0, (struct sockaddr*)&from, &size); + + dhcp_request = 0; + + if(p->xid != xid) + continue; + + dhcp_message_type = get_dhcp_option(p, DHCP_MESSAGE_TYPE); + if(!dhcp_message_type) + continue; + else if(*dhcp_message_type != DHCPACK) + continue; + + DbgPrint("DHCPACK received...\n"); + DbgPrint("IP %s obtained from the DHCP server.\n", inet_ntoa(p->yiaddr)); + break; + } + + close(fd); + + return 0; +} + + + +/* + * Command table registration + * ========================== + */ + +static const Cmd Cmds[] = +{ + {"Network"}, + {"lwdhcp", "", 0, + "Light weight DHCP client", + lwdhcp, 1, 99, CMD_REPEAT}, + {0, 0} +}; + +static void init_cmd __P((void)) __attribute__ ((constructor)); + + static void +init_cmd() +{ + cmdlist_expand(Cmds, 1); +} + + + + + diff --git a/pmon/cmds/lwdhcp/lwdhcp.h b/pmon/cmds/lwdhcp/lwdhcp.h new file mode 100644 index 00000000..d4c60632 --- /dev/null +++ b/pmon/cmds/lwdhcp/lwdhcp.h @@ -0,0 +1,80 @@ +#ifndef __LWDHCP__ +#define __LWDHCP__ + +/* +#include +#include +#include +#include + +#ifdef KERNEL +#undef KERNEL +#include +#else +#include +#endif +*/ + +//#include +#include +//#include + + +#ifndef PMON + #ifndef __LINUX_TYPES_H_ + #define __LINUX_TYPES_H_ + + typedef unsigned char u8; + typedef unsigned short u16; + typedef unsigned int u32; + + typedef signed char s8; + typedef signed short s16; + typedef signed long s32; + + typedef signed int sint; + + typedef signed long slong; + #endif /* __LINUX_TYPES_H_ */ +#else +// typedef uint8_t u8; +// typedef uint16_t u16; +// typedef uint32_t u32; + +#endif + + + +#define LWDHCP_DEBUG 1 + +#ifdef LWDHCP_DEBUG + #define DbgPrint(str, args...) printf(str, ##args) + #define PERROR(str) perror(str) +#else + #define DbgPrint(str, args...) + #define PERROR(str) +#endif + + +#define LWDHCP_MESSAGE 1 + +#ifdef LWDHCP_MESSAGE + #define Message(str, args...) printf(str, ##args) +#else + #define Message(str, args...) +#endif + + +struct client_config_t +{ +#define INTERFACE_MAXLEN 20 + char interface[INTERFACE_MAXLEN]; + char arp[16]; //store the MAC address + + u_int32_t addr; + int ifindex; +}; + +extern struct client_config_t client_config; + +#endif // __LWDHCP__ diff --git a/pmon/cmds/lwdhcp/options.c b/pmon/cmds/lwdhcp/options.c new file mode 100644 index 00000000..836fd4d1 --- /dev/null +++ b/pmon/cmds/lwdhcp/options.c @@ -0,0 +1,233 @@ +/* + * options.c -- DHCP server option packet tools + * Rewrite by Russ Dill July 2001 + */ + +#include +#include + +#include "options.h" +#include "packet.h" +#include "lwdhcp.h" + + +/* supported options are easily added here */ +struct dhcp_option dhcp_options[] = { + /* name[10] flags code */ + {"subnet", OPTION_IP | OPTION_REQ, 0x01}, + {"timezone", OPTION_S32, 0x02}, + {"router", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x03}, + {"timesvr", OPTION_IP | OPTION_LIST, 0x04}, + {"namesvr", OPTION_IP | OPTION_LIST, 0x05}, + {"dns", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x06}, + {"logsvr", OPTION_IP | OPTION_LIST, 0x07}, + {"cookiesvr", OPTION_IP | OPTION_LIST, 0x08}, + {"lprsvr", OPTION_IP | OPTION_LIST, 0x09}, + {"hostname", OPTION_STRING | OPTION_REQ, 0x0c}, + {"bootsize", OPTION_U16, 0x0d}, + {"domain", OPTION_STRING | OPTION_REQ, 0x0f}, + {"swapsvr", OPTION_IP, 0x10}, + //We had the possibility for the client to ask for a rootpath + //closes http://bugs.debian.org/279110 (ericvb@debian.org) + //{"rootpath", OPTION_STRING, 0x11}, + {"rootpath", OPTION_STRING | OPTION_REQ, 0x11}, + {"ipttl", OPTION_U8, 0x17}, + {"mtu", OPTION_U16, 0x1a}, + {"broadcast", OPTION_IP | OPTION_REQ, 0x1c}, + {"nisdomain", OPTION_STRING | OPTION_REQ, 0x28}, + {"nissrv", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x29}, + {"ntpsrv", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x2a}, + {"wins", OPTION_IP | OPTION_LIST, 0x2c}, + {"requestip", OPTION_IP, 0x32}, + {"lease", OPTION_U32, 0x33}, + {"dhcptype", OPTION_U8, 0x35}, + {"serverid", OPTION_IP, 0x36}, + {"message", OPTION_STRING, 0x38}, + {"tftp", OPTION_STRING, 0x42}, + {"bootfile", OPTION_STRING, 0x43}, + {"wpad", OPTION_STRING, 0xfc}, + {"", 0x00, 0x00} +}; + +/* Lengths of the different option types */ +int option_lengths[] = { + [OPTION_IP] = 4, + [OPTION_IP_PAIR] = 8, + [OPTION_BOOLEAN] = 1, + [OPTION_STRING] = 1, + [OPTION_U8] = 1, + [OPTION_U16] = 2, + [OPTION_S16] = 2, + [OPTION_U32] = 4, + [OPTION_S32] = 4 +}; + + +/* get an option with bounds checking (warning, not aligned). */ +uint8_t *get_dhcp_option(struct dhcp_packet *packet, int code) +{ + int i, length; + uint8_t *optionptr; + int over = 0, done = 0, curr = OPTION_FIELD; + + optionptr = packet->options; + i = 0; + length = 308; + while (!done) { + if (i >= length) { + DbgPrint("bogus packet, option fields too long.\n"); + return NULL; + } + if (optionptr[i + OPT_CODE] == code) { + if (i + 1 + optionptr[i + OPT_LEN] >= length) { + DbgPrint("bogus packet, option fields too long.\n"); + return NULL; + } + return optionptr + i + 2; + } + switch (optionptr[i + OPT_CODE]) { + case DHCP_PADDING: + i++; + break; + case DHCP_OPTION_OVER: + if (i + 1 + optionptr[i + OPT_LEN] >= length) { + DbgPrint("bogus packet, option fields too long.\n"); + return NULL; + } + over = optionptr[i + 3]; + i += optionptr[OPT_LEN] + 2; + break; + case DHCP_END: + if (curr == OPTION_FIELD && over & FILE_FIELD) { + optionptr = packet->file; + i = 0; + length = 128; + curr = FILE_FIELD; + } else if (curr == FILE_FIELD && over & SNAME_FIELD) { + optionptr = packet->sname; + i = 0; + length = 64; + curr = SNAME_FIELD; + } else done = 1; + break; + default: + i += optionptr[OPT_LEN + i] + 2; + } + } + return NULL; +} + + +/* return the position of the 'end' option (no bounds checking) */ +int end_option(uint8_t *optionptr) +{ + int i = 0; + + while (optionptr[i] != DHCP_END) { + if (optionptr[i] == DHCP_PADDING) i++; + else i += optionptr[i + OPT_LEN] + 2; + } + return i; +} + + +/* add an option string to the options (an option string contains an option code, + * length, then data) */ +int add_option_string(uint8_t *optionptr, uint8_t *string) +{ + int end = end_option(optionptr); + + /* end position + string length + option code/length + end option */ + if (end + string[OPT_LEN] + 2 + 1 >= 308) { + DbgPrint("Option 0x%02x did not fit into the packet!\n", string[OPT_CODE]); + return 0; + } + //DbgPrint("adding option 0x%02x\n", string[OPT_CODE]); + memcpy(optionptr + end, string, string[OPT_LEN] + 2); + optionptr[end + string[OPT_LEN] + 2] = DHCP_END; + return string[OPT_LEN] + 2; +} + + +/* add a one to four byte option to a packet */ +int add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data) +{ + char length = 0; + int i; + uint8_t option[2 + 4]; + uint8_t *u8; + uint16_t *u16; + uint32_t *u32; + uint32_t aligned; + u8 = (uint8_t *) &aligned; + u16 = (uint16_t *) &aligned; + u32 = &aligned; + + for (i = 0; dhcp_options[i].code; i++) + if (dhcp_options[i].code == code) { + length = option_lengths[dhcp_options[i].flags & TYPE_MASK]; + } + + if (!length) { + DbgPrint("Could not add option 0x%02x\n", code); + return 0; + } + + option[OPT_CODE] = code; + option[OPT_LEN] = length; + + switch (length) { + case 1: *u8 = data; break; + case 2: *u16 = data; break; + case 4: *u32 = data; break; + } + memcpy(option + 2, &aligned, length); + return add_option_string(optionptr, option); +} + + +/* find option 'code' in opt_list */ +struct option_set *find_option(struct option_set *opt_list, char code) +{ + while (opt_list && opt_list->data[OPT_CODE] < code) + opt_list = opt_list->next; + + if (opt_list && opt_list->data[OPT_CODE] == code) return opt_list; + else return NULL; +} + + +/* add an option to the opt_list */ +void attach_option(struct option_set **opt_list, struct dhcp_option *option, char *buffer, int length) +{ + struct option_set *existing, *new, **curr; + + /* add it to an existing option */ + if ((existing = find_option(*opt_list, option->code))) { + DbgPrint("Attaching option %s to existing member of list\n", option->name); + if (option->flags & OPTION_LIST) { + if (existing->data[OPT_LEN] + length <= 255) { + existing->data = realloc(existing->data, + existing->data[OPT_LEN] + length + 2); + memcpy(existing->data + existing->data[OPT_LEN] + 2, buffer, length); + existing->data[OPT_LEN] += length; + } /* else, ignore the data, we could put this in a second option in the future */ + } /* else, ignore the new data */ + } else { + DbgPrint("Attaching option %s to list\n", option->name); + + /* make a new option */ + new = malloc(sizeof(struct option_set)); + new->data = malloc(length + 2); + new->data[OPT_CODE] = option->code; + new->data[OPT_LEN] = length; + memcpy(new->data + 2, buffer, length); + + curr = opt_list; + while (*curr && (*curr)->data[OPT_CODE] < option->code) + curr = &(*curr)->next; + + new->next = *curr; + *curr = new; + } +} diff --git a/pmon/cmds/lwdhcp/options.h b/pmon/cmds/lwdhcp/options.h new file mode 100644 index 00000000..294fdc9a --- /dev/null +++ b/pmon/cmds/lwdhcp/options.h @@ -0,0 +1,53 @@ +/* options.h */ +#ifndef _OPTIONS_H +#define _OPTIONS_H + +#include "packet.h" + +#define TYPE_MASK 0x0F + +enum { + OPTION_IP=1, + OPTION_IP_PAIR, + OPTION_STRING, + OPTION_BOOLEAN, + OPTION_U8, + OPTION_U16, + OPTION_S16, + OPTION_U32, + OPTION_S32 +}; + +#define OPTION_REQ 0x10 /* have the client request this option */ +#define OPTION_LIST 0x20 /* There can be a list of 1 or more of these */ + +struct dhcp_option { + char name[10]; + char flags; + uint8_t code; +}; + + +struct option_set { + uint8_t *data; + struct option_set *next; +}; + +struct static_lease { + uint8_t *mac; + uint32_t *ip; + struct static_lease *next; +}; + + +extern struct dhcp_option dhcp_options[]; +extern int option_lengths[]; + +uint8_t *get_option(struct dhcp_packet *packet, int code); +int end_option(uint8_t *optionptr); +int add_option_string(uint8_t *optionptr, uint8_t *string); +int add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data); +struct option_set *find_option(struct option_set *opt_list, char code); +void attach_option(struct option_set **opt_list, struct dhcp_option *option, char *buffer, int length); + +#endif diff --git a/pmon/cmds/lwdhcp/packet.c b/pmon/cmds/lwdhcp/packet.c new file mode 100644 index 00000000..7ac03598 --- /dev/null +++ b/pmon/cmds/lwdhcp/packet.c @@ -0,0 +1,249 @@ +#include +#include +#include +#include + +#ifdef KERNEL +#undef KERNEL +#include +#include +#include +#else +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "packet.h" +#include "lwdhcp.h" +#include "options.h" + +void init_header(struct dhcp_packet *packet, char type) +{ + memset(packet, 0, sizeof(struct dhcp_packet)); + switch (type) { + case DHCPDISCOVER: + case DHCPREQUEST: + case DHCPRELEASE: + case DHCPINFORM: + packet->op = BOOTREQUEST; + break; + case DHCPOFFER: + case DHCPACK: + case DHCPNAK: + packet->op = BOOTREPLY; + } + packet->htype = ETH_10MB; + packet->hlen = ETH_10MB_LEN; + packet->cookie = htonl(DHCP_MAGIC); + packet->options[0] = DHCP_END; + add_simple_option(packet->options, DHCP_MESSAGE_TYPE, type); +} + + +/* initialize a packet with the proper defaults */ +static void init_packet(struct dhcp_packet *packet, char type) +{ + init_header(packet, type); + + memcpy(packet->chaddr, client_config.arp, 6); +} + + +uint16_t checksum(void *addr, int count) +{ + /* Compute Internet Checksum for "count" bytes + * beginning at location "addr". + */ + register int32_t sum = 0; + uint16_t *source = (uint16_t *) addr; + + while (count > 1) { + /* This is the inner loop */ + sum += *source++; + count -= 2; + } + + /* Add left-over byte, if any */ + if (count > 0) { + /* Make sure that the left-over byte is added correctly both + * with little and big endian hosts */ + uint16_t tmp = 0; + *(uint8_t *) (&tmp) = * (uint8_t *) source; + sum += tmp; + } + /* Fold 32-bit sum to 16 bits */ + while (sum >> 16) + sum = (sum & 0xffff) + (sum >> 16); + + return ~sum; +} + + + +#ifndef PMON +int raw_packet(struct dhcp_packet *payload, uint32_t source_ip, int source_port, + uint32_t dest_ip, int dest_port, uint8_t *dest_arp, int ifindex) +{ + int fd; + int result; + struct sockaddr_ll dest; + struct udp_dhcp_packet packet; + + if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) { + perror("socket call failed"); + return -1; + } + + memset(&dest, 0, sizeof(dest)); + memset(&packet, 0, sizeof(packet)); + + dest.sll_family = AF_PACKET; + dest.sll_protocol = htons(ETH_P_IP); + dest.sll_ifindex = ifindex; + dest.sll_halen = 6; + memcpy(dest.sll_addr, dest_arp, 6); + if (bind(fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_ll)) < 0) + { + perror("bind call failed"); + close(fd); + return -1; + } + packet.ip.protocol = IPPROTO_UDP; + packet.ip.saddr = source_ip; + packet.ip.daddr = dest_ip; + packet.udp.source = htons(source_port); + packet.udp.dest = htons(dest_port); + packet.udp.len = htons(sizeof(packet.udp) + sizeof(struct dhcp_packet)); /* cheat on the psuedo-header */ + packet.ip.tot_len = packet.udp.len; + memcpy(&(packet.data), payload, sizeof(struct dhcp_packet)); + packet.udp.check = checksum(&packet, sizeof(struct udp_dhcp_packet)); + + packet.ip.tot_len = htons(sizeof(struct udp_dhcp_packet)); + packet.ip.ihl = sizeof(packet.ip) >> 2; + packet.ip.version = IPVERSION; + packet.ip.ttl = IPDEFTTL; + packet.ip.check = checksum(&(packet.ip), sizeof(packet.ip)); + + result = sendto(fd, &packet, sizeof(struct udp_dhcp_packet), 0, (struct sockaddr *) &dest, sizeof(dest)); + if (result <= 0) { + perror("write on socket failed"); + } + close(fd); + return result; +} +#else +int raw_packet(struct dhcp_packet *payload, uint32_t source_ip, int source_port, + uint32_t dest_ip, int dest_port, uint8_t *dest_arp, int ifindex) +{ + int n; + int sock; + struct sockaddr_in clnt, srvr; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) { + perror ("bootp socket"); + return -1; + } + + n = 1; + if (setsockopt (sock, SOL_SOCKET, SO_BROADCAST, &n, sizeof (n)) < 0) { + perror ("bootp setsockopt(BROADCAST)"); + close (sock); + return -1; + } + /* + if (setsockopt (sock, SOL_SOCKET, SO_DONTROUTE, &n, sizeof (n)) < 0) { + perror ("bootp setsockopt(DONTROUTE)"); + close (sock); + return -1; + }*/ + + bzero((char *)&clnt, sizeof(clnt)); + clnt.sin_family = AF_INET; + clnt.sin_port = htons(CLIENT_PORT+2); + clnt.sin_addr.s_addr = INADDR_ANY; + + if (bind (sock, (struct sockaddr *)&clnt, sizeof(clnt)) < 0) { + PERROR ("bind failed"); + close (sock); + return -1; + } + + //change_promisc(sock, 0); + + bzero ((char *)&srvr, sizeof (srvr)); + srvr.sin_family = AF_INET; + srvr.sin_addr.s_addr = INADDR_BROADCAST; + srvr.sin_port = htons (SERVER_PORT); + + n = sendto(sock, payload, sizeof(struct dhcp_packet), 0, (struct sockaddr *)&srvr, sizeof(srvr)); + if(n < 0) + { + PERROR("sendto failed"); + close(sock); + return -1; + } + + close(sock); + + return 0; +} + +#endif + + +/* Add a parameter request list for stubborn DHCP servers. Pull the data + * from the struct in options.c. Don't do bounds checking here because it + * goes towards the head of the packet. */ +static void add_requests(struct dhcp_packet *packet) +{ + int end = end_option(packet->options); + int i, len = 0; + + packet->options[end + OPT_CODE] = DHCP_PARAM_REQ; + for (i = 0; dhcp_options[i].code; i++) + if (dhcp_options[i].flags & OPTION_REQ) + packet->options[end + OPT_DATA + len++] = dhcp_options[i].code; + packet->options[end + OPT_LEN] = len; + packet->options[end + OPT_DATA + len] = DHCP_END; + +} + +int send_request(unsigned long xid, uint32_t server, uint32_t requested_ip) +{ + struct dhcp_packet packet; + + init_packet(&packet, DHCPREQUEST); + packet.xid = xid; + + add_simple_option(packet.options, DHCP_SERVER_ID, server); + add_simple_option(packet.options, DHCP_REQUESTED_IP, requested_ip); + + DbgPrint("Sending DHCPREQUEST...\n"); + + return raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, + SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex); +} + +int send_discover(unsigned long xid) +{ + struct dhcp_packet packet; + + init_packet(&packet, DHCPDISCOVER); + packet.xid = xid; + + DbgPrint("Sending DHCPDISCOVER...\n"); + return raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, + SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex); +} + diff --git a/pmon/cmds/lwdhcp/packet.h b/pmon/cmds/lwdhcp/packet.h new file mode 100644 index 00000000..268327c4 --- /dev/null +++ b/pmon/cmds/lwdhcp/packet.h @@ -0,0 +1,309 @@ +#ifndef __LWDHCP_PACKET__ +#define __LWDHCP_PACKET__ + +#undef KERNEL +#include +#include +#include +#include +#include +//#include +//#include + + +/* DHCP protocol -- see RFC 2131 */ +#define SERVER_PORT 67 +#define CLIENT_PORT 68 + +#define DHCP_MAGIC 0x63825363 + +/* DHCP option codes (partial list) */ +#define DHCP_PADDING 0x00 +#define DHCP_SUBNET 0x01 +#define DHCP_TIME_OFFSET 0x02 +#define DHCP_ROUTER 0x03 +#define DHCP_TIME_SERVER 0x04 +#define DHCP_NAME_SERVER 0x05 +#define DHCP_DNS_SERVER 0x06 +#define DHCP_LOG_SERVER 0x07 +#define DHCP_COOKIE_SERVER 0x08 +#define DHCP_LPR_SERVER 0x09 +#define DHCP_HOST_NAME 0x0c +#define DHCP_BOOT_SIZE 0x0d +#define DHCP_DOMAIN_NAME 0x0f +#define DHCP_SWAP_SERVER 0x10 +#define DHCP_ROOT_PATH 0x11 +#define DHCP_IP_TTL 0x17 +#define DHCP_MTU 0x1a +#define DHCP_BROADCAST 0x1c +#define DHCP_NTP_SERVER 0x2a +#define DHCP_WINS_SERVER 0x2c +#define DHCP_REQUESTED_IP 0x32 +#define DHCP_LEASE_TIME 0x33 +#define DHCP_OPTION_OVER 0x34 +#define DHCP_MESSAGE_TYPE 0x35 +#define DHCP_SERVER_ID 0x36 +#define DHCP_PARAM_REQ 0x37 +#define DHCP_MESSAGE 0x38 +#define DHCP_MAX_SIZE 0x39 +#define DHCP_T1 0x3a +#define DHCP_T2 0x3b +#define DHCP_VENDOR 0x3c +#define DHCP_CLIENT_ID 0x3d +#define DHCP_FQDN 0x51 + +#define DHCP_END 0xFF + + +#define BOOTREQUEST 1 +#define BOOTREPLY 2 + +#define ETH_10MB 1 +#define ETH_10MB_LEN 6 + +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 +#define DHCPINFORM 8 + +#define BROADCAST_FLAG 0x8000 + +#define OPTION_FIELD 0 +#define FILE_FIELD 1 +#define SNAME_FIELD 2 + + +#define DHCP_UDP_OVERHEAD (20 + /* IP header */ \ + 8) /* UDP header */ +#define DHCP_SNAME_LEN 64 +#define DHCP_FILE_LEN 128 +#define DHCP_FIXED_NON_UDP 236 +#define DHCP_FIXED_LEN (DHCP_FIXED_NON_UDP + DHCP_UDP_OVERHEAD) +/* Everything but options. */ +#define DHCP_MTU_MAX 1500 +#define DHCP_OPTION_LEN (308) //(DHCP_MTU_MAX - DHCP_FIXED_LEN) + +#define BOOTP_MIN_LEN 300 +#define DHCP_MIN_LEN 548 + + + +/* miscellaneous defines */ +#define MAC_BCAST_ADDR (uint8_t *) "\xff\xff\xff\xff\xff\xff" +#define OPT_CODE 0 +#define OPT_LEN 1 +#define OPT_DATA 2 + + + + +struct dhcp_packet { + u_int8_t op; /* 0: Message opcode/type */ + u_int8_t htype; /* 1: Hardware addr type (net/if_types.h) */ + u_int8_t hlen; /* 2: Hardware addr length */ + u_int8_t hops; /* 3: Number of relay agent hops from client */ + u_int32_t xid; /* 4: Transaction ID */ + u_int16_t secs; /* 8: Seconds since client started looking */ + u_int16_t flags; /* 10: Flag bits */ + struct in_addr ciaddr; /* 12: Client IP address (if already in use) */ + struct in_addr yiaddr; /* 16: Client IP address */ + struct in_addr siaddr; /* 18: IP address of next server to talk to */ + struct in_addr giaddr; /* 20: DHCP relay agent IP address */ + unsigned char chaddr [16]; /* 24: Client hardware address */ + char sname [DHCP_SNAME_LEN]; /* 40: Server name */ + char file [DHCP_FILE_LEN]; /* 104: Boot filename */ + u_int32_t cookie; + unsigned char options [DHCP_OPTION_LEN - 4]; + /* 212: Optional parameters + (actual length dependent on MTU). */ +}; + +#define IPVERSION 4 + +struct iphdr +{ +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int ihl:4; + unsigned int version:4; +#elif __BYTE_ORDER == __BIG_ENDIAN + unsigned int version:4; + unsigned int ihl:4; +#else +# error "Please fix " +#endif + u_int8_t tos; + u_int16_t tot_len; + u_int16_t id; + u_int16_t frag_off; + u_int8_t ttl; + u_int8_t protocol; + u_int16_t check; + u_int32_t saddr; + u_int32_t daddr; + /*The options start here. */ +}; + + +/* UDP header as specified by RFC 768, August 1980. */ +#ifdef __FAVOR_BSD + +struct udphdr +{ + u_int16_t uh_sport; /* source port */ + u_int16_t uh_dport; /* destination port */ + u_int16_t uh_ulen; /* udp length */ + u_int16_t uh_sum; /* udp checksum */ +}; + +#else + +struct udphdr +{ + u_int16_t source; + u_int16_t dest; + u_int16_t len; + u_int16_t check; +}; +#endif + + + + +struct udp_dhcp_packet { + struct iphdr ip; + struct udphdr udp; + struct dhcp_packet data; +}; + + +/* BOOTP (rfc951) message types */ +#define BOOTREQUEST 1 +#define BOOTREPLY 2 + +/* Possible values for flags field... */ +#define BOOTP_BROADCAST 32768L + +/* Possible values for hardware type (htype) field... */ +#define HTYPE_ETHER 1 /* Ethernet 10Mbps */ +#define HTYPE_IEEE802 6 /* IEEE 802.2 Token Ring... */ +#define HTYPE_FDDI 8 /* FDDI... */ + +/* Magic cookie validating dhcp options field (and bootp vendor + extensions field). */ +#define DHCP_OPTIONS_COOKIE "\143\202\123\143" + +/* DHCP Option codes: */ + +#define DHO_PAD 0 +#define DHO_SUBNET_MASK 1 +#define DHO_TIME_OFFSET 2 +#define DHO_ROUTERS 3 +#define DHO_TIME_SERVERS 4 +#define DHO_NAME_SERVERS 5 +#define DHO_DOMAIN_NAME_SERVERS 6 +#define DHO_LOG_SERVERS 7 +#define DHO_COOKIE_SERVERS 8 +#define DHO_LPR_SERVERS 9 +#define DHO_IMPRESS_SERVERS 10 +#define DHO_RESOURCE_LOCATION_SERVERS 11 +#define DHO_HOST_NAME 12 +#define DHO_BOOT_SIZE 13 +#define DHO_MERIT_DUMP 14 +#define DHO_DOMAIN_NAME 15 +#define DHO_SWAP_SERVER 16 +#define DHO_ROOT_PATH 17 +#define DHO_EXTENSIONS_PATH 18 +#define DHO_IP_FORWARDING 19 +#define DHO_NON_LOCAL_SOURCE_ROUTING 20 +#define DHO_POLICY_FILTER 21 +#define DHO_MAX_DGRAM_REASSEMBLY 22 +#define DHO_DEFAULT_IP_TTL 23 +#define DHO_PATH_MTU_AGING_TIMEOUT 24 +#define DHO_PATH_MTU_PLATEAU_TABLE 25 +#define DHO_INTERFACE_MTU 26 +#define DHO_ALL_SUBNETS_LOCAL 27 +#define DHO_BROADCAST_ADDRESS 28 +#define DHO_PERFORM_MASK_DISCOVERY 29 +#define DHO_MASK_SUPPLIER 30 +#define DHO_ROUTER_DISCOVERY 31 +#define DHO_ROUTER_SOLICITATION_ADDRESS 32 +#define DHO_STATIC_ROUTES 33 +#define DHO_TRAILER_ENCAPSULATION 34 +#define DHO_ARP_CACHE_TIMEOUT 35 +#define DHO_IEEE802_3_ENCAPSULATION 36 +#define DHO_DEFAULT_TCP_TTL 37 +#define DHO_TCP_KEEPALIVE_INTERVAL 38 +#define DHO_TCP_KEEPALIVE_GARBAGE 39 +#define DHO_NIS_DOMAIN 40 +#define DHO_NIS_SERVERS 41 +#define DHO_NTP_SERVERS 42 +#define DHO_VENDOR_ENCAPSULATED_OPTIONS 43 +#define DHO_NETBIOS_NAME_SERVERS 44 +#define DHO_NETBIOS_DD_SERVER 45 +#define DHO_NETBIOS_NODE_TYPE 46 +#define DHO_NETBIOS_SCOPE 47 +#define DHO_FONT_SERVERS 48 +#define DHO_X_DISPLAY_MANAGER 49 +#define DHO_DHCP_REQUESTED_ADDRESS 50 +#define DHO_DHCP_LEASE_TIME 51 +#define DHO_DHCP_OPTION_OVERLOAD 52 +#define DHO_DHCP_MESSAGE_TYPE 53 +#define DHO_DHCP_SERVER_IDENTIFIER 54 +#define DHO_DHCP_PARAMETER_REQUEST_LIST 55 +#define DHO_DHCP_MESSAGE 56 +#define DHO_DHCP_MAX_MESSAGE_SIZE 57 +#define DHO_DHCP_RENEWAL_TIME 58 +#define DHO_DHCP_REBINDING_TIME 59 +#define DHO_VENDOR_CLASS_IDENTIFIER 60 +#define DHO_DHCP_CLIENT_IDENTIFIER 61 +#define DHO_NWIP_DOMAIN_NAME 62 +#define DHO_NWIP_SUBOPTIONS 63 +#define DHO_USER_CLASS 77 +#define DHO_FQDN 81 +#define DHO_DHCP_AGENT_OPTIONS 82 +#define DHO_SUBNET_SELECTION 118 /* RFC3011! */ +/* The DHO_AUTHENTICATE option is not a standard yet, so I've + allocated an option out of the "local" option space for it on a + temporary basis. Once an option code number is assigned, I will + immediately and shamelessly break this, so don't count on it + continuing to work. */ +#define DHO_AUTHENTICATE 210 + +#define DHO_END 255 + +/* DHCP message types. */ +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 +#define DHCPINFORM 8 + +/* Relay Agent Information option subtypes: */ +#define RAI_CIRCUIT_ID 1 +#define RAI_REMOTE_ID 2 +#define RAI_AGENT_ID 3 + +/* FQDN suboptions: */ +#define FQDN_NO_CLIENT_UPDATE 1 +#define FQDN_SERVER_UPDATE 2 +#define FQDN_ENCODED 3 +#define FQDN_RCODE1 4 +#define FQDN_RCODE2 5 +#define FQDN_HOSTNAME 6 +#define FQDN_DOMAINNAME 7 +#define FQDN_FQDN 8 +#define FQDN_SUBOPTION_COUNT 8 + + +extern int send_request(unsigned long xid, uint32_t server, uint32_t requested_ip); +extern int send_discover(unsigned long xid); +extern int get_raw_packet(struct dhcp_packet *payload, int fd); + +#endif // __LWDHCP_PACKET__ diff --git a/pmon/netio/bootp.c b/pmon/netio/bootp.c index c8793d1e..9c755faf 100644 --- a/pmon/netio/bootp.c +++ b/pmon/netio/bootp.c @@ -98,7 +98,7 @@ static void vend_rfc1048 (struct bootparams *, u_char *, u_int); static int xid; static jmp_buf jmpb; -static int +int getethaddr (unsigned char *eaddr, char *ifc) { struct ifnet *ifp; diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index af59e15a..d7ac95ea 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -65,6 +65,8 @@ #include #include #include +#include "cmd_lwhdcp.h" +extern int dhcp_request; #ifndef IPFORWARDING #ifdef GATEWAY @@ -393,6 +395,10 @@ ipv4_input(struct mbuf *m, ...) /* * Check our list of addresses, to see if the packet is for us. */ +#if NCMD_LWHDCP + if(dhcp_request) + goto ours; +#endif if ((ia = in_iawithaddr(ip->ip_dst, m)) != NULL && (ia->ia_ifp->if_flags & IFF_UP)) goto ours; diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index d57e3faf..dc4223ec 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -94,6 +94,9 @@ extern int ipv6_defhoplmt; #endif /* INET6 */ +#include "cmd_lwhdcp.h" +extern int dhcp_request; + /* * UDP protocol implementation. * Per RFC 768, August, 1980. @@ -320,7 +323,11 @@ udp_input(m, va_alist) (ip && in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif))) { #else /* INET6 */ if (IN_MULTICAST(ip->ip_dst.s_addr) || - in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) { + in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif) +#if NCMD_LWHDCP + || dhcp_request +#endif +) { #endif /* INET6 */ struct socket *last; /*