Browse Source

add dhcpclent support

git-svn-id: file:///svn/pmon-all/pmon-all@98 214b0138-1524-0410-9122-e5cb4b5bc56c
master
root 17 years ago
parent
commit
f468be4538
  1. 2
      Targets/Bonito2edev/conf/Bonito
  2. 5
      conf/files
  3. 18
      pmon/cmds/lwdhcp/Makefile
  4. 362
      pmon/cmds/lwdhcp/lwdhcp.c
  5. 80
      pmon/cmds/lwdhcp/lwdhcp.h
  6. 233
      pmon/cmds/lwdhcp/options.c
  7. 53
      pmon/cmds/lwdhcp/options.h
  8. 249
      pmon/cmds/lwdhcp/packet.c
  9. 309
      pmon/cmds/lwdhcp/packet.h
  10. 2
      pmon/netio/bootp.c
  11. 6
      sys/netinet/ip_input.c
  12. 9
      sys/netinet/udp_usrreq.c

2
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

5
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

18
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

362
pmon/cmds/lwdhcp/lwdhcp.c

@ -0,0 +1,362 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// Light weight DHCP client //
// //
/////////////////////////////////////////////////////////////////////////////////////////////////////
#include <sys/param.h>
#include <sys/file.h>
#include <sys/syslog.h>
#include <sys/endian.h>
#ifdef PMON
#ifdef KERNEL
#undef KERNEL
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#else
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#endif
#define KERNEL
#include <pmon/netio/bootp.h>
#include <sys/types.h>
#include <sys/net/if.h>
#else
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#endif
#include <pmon.h>
#include <setjmp.h>
#include <signal.h>
#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);
}

80
pmon/cmds/lwdhcp/lwdhcp.h

@ -0,0 +1,80 @@
#ifndef __LWDHCP__
#define __LWDHCP__
/*
#include <sys/param.h>
#include <sys/file.h>
#include <sys/syslog.h>
#include <sys/endian.h>
#ifdef KERNEL
#undef KERNEL
#include <sys/socket.h>
#else
#include <sys/socket.h>
#endif
*/
//#include <sys/types.h>
#include <stdio.h>
//#include <linux/types.h>
#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__

233
pmon/cmds/lwdhcp/options.c

@ -0,0 +1,233 @@
/*
* options.c -- DHCP server option packet tools
* Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
*/
#include <stdlib.h>
#include <string.h>
#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;
}
}

53
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

249
pmon/cmds/lwdhcp/packet.c

@ -0,0 +1,249 @@
#include <sys/param.h>
#include <sys/file.h>
#include <sys/syslog.h>
#include <sys/endian.h>
#ifdef KERNEL
#undef KERNEL
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#else
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#endif
#include <termio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <string.h>
#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);
}

309
pmon/cmds/lwdhcp/packet.h

@ -0,0 +1,309 @@
#ifndef __LWDHCP_PACKET__
#define __LWDHCP_PACKET__
#undef KERNEL
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/time.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
//#include <netinet/ip.h>
//#include <netinet/udp.h>
/* 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 <bits/endian.h>"
#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__

2
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;

6
sys/netinet/ip_input.c

@ -65,6 +65,8 @@
#include <netinet/ip_var.h>
#include <netinet/ip_icmp.h>
#include <netinet/ip_ipsp.h>
#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;

9
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;
/*

Loading…
Cancel
Save