dhcp.c 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526
  1. /* dhcp.c - DHCP client for dynamic network configuration.
  2. *
  3. * Copyright 2012 Madhur Verma <mad.flexi@gmail.com>
  4. * Copyright 2013 Kyungwan Han <asura321@gmail.com>
  5. *
  6. * Not in SUSv4.
  7. USE_DHCP(NEWTOY(dhcp, "V:H:F:x*r:O*A#<0=20T#<0=3t#<0=3s:p:i:SBRCaovqnbf", TOYFLAG_SBIN|TOYFLAG_ROOTONLY))
  8. config DHCP
  9. bool "dhcp"
  10. default n
  11. help
  12. usage: dhcp [-fbnqvoCRB] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]
  13. [-H HOSTNAME] [-V VENDOR] [-x OPT:VAL] [-O OPT]
  14. Configure network dynamically using DHCP.
  15. -i Interface to use (default eth0)
  16. -p Create pidfile
  17. -s Run PROG at DHCP events (default /usr/share/dhcp/default.script)
  18. -B Request broadcast replies
  19. -t Send up to N discover packets
  20. -T Pause between packets (default 3 seconds)
  21. -A Wait N seconds after failure (default 20)
  22. -f Run in foreground
  23. -b Background if lease is not obtained
  24. -n Exit if lease is not obtained
  25. -q Exit after obtaining lease
  26. -R Release IP on exit
  27. -S Log to syslog too
  28. -a Use arping to validate offered address
  29. -O Request option OPT from server (cumulative)
  30. -o Don't request any options (unless -O is given)
  31. -r Request this IP address
  32. -x OPT:VAL Include option OPT in sent packets (cumulative)
  33. -F Ask server to update DNS mapping for NAME
  34. -H Send NAME as client hostname (default none)
  35. -V VENDOR Vendor identifier (default 'toybox VERSION')
  36. -C Don't send MAC as client identifier
  37. -v Verbose
  38. Signals:
  39. USR1 Renew current lease
  40. USR2 Release current lease
  41. */
  42. #define FOR_dhcp
  43. #include "toys.h"
  44. // TODO: headers not in posix:
  45. #include <netinet/ip.h>
  46. #include <netinet/udp.h>
  47. #include <netpacket/packet.h>
  48. #include <linux/filter.h> //FIXME: linux specific. fix for other OS ports
  49. #include <linux/if_ether.h>
  50. GLOBALS(
  51. char *iface;
  52. char *pidfile;
  53. char *script;
  54. long retries;
  55. long timeout;
  56. long tryagain;
  57. struct arg_list *req_opt;
  58. char *req_ip;
  59. struct arg_list *pkt_opt;
  60. char *fdn_name;
  61. char *hostname;
  62. char *vendor_cls;
  63. )
  64. #define STATE_INIT 0
  65. #define STATE_REQUESTING 1
  66. #define STATE_BOUND 2
  67. #define STATE_RENEWING 3
  68. #define STATE_REBINDING 4
  69. #define STATE_RENEW_REQUESTED 5
  70. #define STATE_RELEASED 6
  71. #define BOOTP_BROADCAST 0x8000
  72. #define DHCP_MAGIC 0x63825363
  73. #define DHCP_REQUEST 1
  74. #define DHCP_REPLY 2
  75. #define DHCP_HTYPE_ETHERNET 1
  76. #define DHCPC_SERVER_PORT 67
  77. #define DHCPC_CLIENT_PORT 68
  78. #define DHCPDISCOVER 1
  79. #define DHCPOFFER 2
  80. #define DHCPREQUEST 3
  81. #define DHCPACK 5
  82. #define DHCPNAK 6
  83. #define DHCPRELEASE 7
  84. #define DHCP_OPTION_PADDING 0x00
  85. #define DHCP_OPTION_SUBNET_MASK 0x01
  86. #define DHCP_OPTION_ROUTER 0x03
  87. #define DHCP_OPTION_DNS_SERVER 0x06
  88. #define DHCP_OPTION_HOST_NAME 0x0c
  89. #define DHCP_OPTION_BROADCAST 0x1c
  90. #define DHCP_OPTION_REQ_IPADDR 0x32
  91. #define DHCP_OPTION_LEASE_TIME 0x33
  92. #define DHCP_OPTION_OVERLOAD 0x34
  93. #define DHCP_OPTION_MSG_TYPE 0x35
  94. #define DHCP_OPTION_SERVER_ID 0x36
  95. #define DHCP_OPTION_REQ_LIST 0x37
  96. #define DHCP_OPTION_MAX_SIZE 0x39
  97. #define DHCP_OPTION_CLIENTID 0x3D
  98. #define DHCP_OPTION_VENDOR 0x3C
  99. #define DHCP_OPTION_FQDN 0x51
  100. #define DHCP_OPTION_END 0xFF
  101. #define DHCP_NUM8 (1<<8)
  102. #define DHCP_NUM16 (1<<9)
  103. #define DHCP_NUM32 DHCP_NUM16 | DHCP_NUM8
  104. #define DHCP_STRING (1<<10)
  105. #define DHCP_STRLST (1<<11)
  106. #define DHCP_IP (1<<12)
  107. #define DHCP_IPLIST (1<<13)
  108. #define DHCP_IPPLST (1<<14)
  109. #define DHCP_STCRTS (1<<15)
  110. #define LOG_SILENT 0x0
  111. #define LOG_CONSOLE 0x1
  112. #define LOG_SYSTEM 0x2
  113. #define MODE_OFF 0
  114. #define MODE_RAW 1
  115. #define MODE_APP 2
  116. static void (*dbg)(char *format, ...);
  117. static void dummy(char *format, ...){
  118. return;
  119. }
  120. typedef struct dhcpc_result_s {
  121. struct in_addr serverid;
  122. struct in_addr ipaddr;
  123. struct in_addr netmask;
  124. struct in_addr dnsaddr;
  125. struct in_addr default_router;
  126. uint32_t lease_time;
  127. } dhcpc_result_t;
  128. typedef struct __attribute__((packed)) dhcp_msg_s {
  129. uint8_t op;
  130. uint8_t htype;
  131. uint8_t hlen;
  132. uint8_t hops;
  133. uint32_t xid;
  134. uint16_t secs;
  135. uint16_t flags;
  136. uint32_t ciaddr;
  137. uint32_t yiaddr;
  138. uint32_t nsiaddr;
  139. uint32_t ngiaddr;
  140. uint8_t chaddr[16];
  141. uint8_t sname[64];
  142. uint8_t file[128];
  143. uint32_t cookie;
  144. uint8_t options[308];
  145. } dhcp_msg_t;
  146. typedef struct __attribute__((packed)) dhcp_raw_s {
  147. struct iphdr iph;
  148. struct udphdr udph;
  149. dhcp_msg_t dhcp;
  150. } dhcp_raw_t;
  151. typedef struct dhcpc_state_s {
  152. uint8_t macaddr[6];
  153. char *iface;
  154. int ifindex;
  155. int sockfd;
  156. int status;
  157. int mode;
  158. uint32_t mask;
  159. struct in_addr ipaddr;
  160. struct in_addr serverid;
  161. dhcp_msg_t pdhcp;
  162. } dhcpc_state_t;
  163. typedef struct option_val_s {
  164. char *key;
  165. uint16_t code;
  166. void *val;
  167. size_t len;
  168. } option_val_t;
  169. struct fd_pair { int rd; int wr; };
  170. static uint32_t xid;
  171. static dhcpc_state_t *state;
  172. static struct fd_pair sigfd;
  173. uint8_t bmacaddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
  174. int set = 1;
  175. uint8_t infomode = LOG_CONSOLE;
  176. uint8_t raw_opt[29];
  177. int raw_optcount = 0;
  178. struct arg_list *x_opt;
  179. in_addr_t server = 0;
  180. static option_val_t *msgopt_list = NULL;
  181. static option_val_t options_list[] = {
  182. {"lease" , DHCP_NUM32 | 0x33, NULL, 0},
  183. {"subnet" , DHCP_IP | 0x01, NULL, 0},
  184. {"broadcast" , DHCP_IP | 0x1c, NULL, 0},
  185. {"router" , DHCP_IP | 0x03, NULL, 0},
  186. {"ipttl" , DHCP_NUM8 | 0x17, NULL, 0},
  187. {"mtu" , DHCP_NUM16 | 0x1a, NULL, 0},
  188. {"hostname" , DHCP_STRING | 0x0c, NULL, 0},
  189. {"domain" , DHCP_STRING | 0x0f, NULL, 0},
  190. {"search" , DHCP_STRLST | 0x77, NULL, 0},
  191. {"nisdomain" , DHCP_STRING | 0x28, NULL, 0},
  192. {"timezone" , DHCP_NUM32 | 0x02, NULL, 0},
  193. {"tftp" , DHCP_STRING | 0x42, NULL, 0},
  194. {"bootfile" , DHCP_STRING | 0x43, NULL, 0},
  195. {"bootsize" , DHCP_NUM16 | 0x0d, NULL, 0},
  196. {"rootpath" , DHCP_STRING | 0x11, NULL, 0},
  197. {"wpad" , DHCP_STRING | 0xfc, NULL, 0},
  198. {"serverid" , DHCP_IP | 0x36, NULL, 0},
  199. {"message" , DHCP_STRING | 0x38, NULL, 0},
  200. {"vlanid" , DHCP_NUM32 | 0x84, NULL, 0},
  201. {"vlanpriority" , DHCP_NUM32 | 0x85, NULL, 0},
  202. {"dns" , DHCP_IPLIST | 0x06, NULL, 0},
  203. {"wins" , DHCP_IPLIST | 0x2c, NULL, 0},
  204. {"nissrv" , DHCP_IPLIST | 0x29, NULL, 0},
  205. {"ntpsrv" , DHCP_IPLIST | 0x2a, NULL, 0},
  206. {"lprsrv" , DHCP_IPLIST | 0x09, NULL, 0},
  207. {"swapsrv" , DHCP_IP | 0x10, NULL, 0},
  208. {"routes" , DHCP_STCRTS | 0x21, NULL, 0},
  209. {"staticroutes" , DHCP_STCRTS | 0x79, NULL, 0},
  210. {"msstaticroutes" , DHCP_STCRTS | 0xf9, NULL, 0},
  211. };
  212. static struct sock_filter filter_instr[] = {
  213. BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
  214. BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6),
  215. BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6),
  216. BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0),
  217. BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2),
  218. BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1),
  219. BPF_STMT(BPF_RET|BPF_K, 0xffffffff), BPF_STMT(BPF_RET|BPF_K, 0),
  220. };
  221. static struct sock_fprog filter_prog = {
  222. .len = ARRAY_LEN(filter_instr),
  223. .filter = (struct sock_filter *) filter_instr,
  224. };
  225. // calculate options size.
  226. static int dhcp_opt_size(uint8_t *optionptr)
  227. {
  228. int i = 0;
  229. for(;optionptr[i] != 0xff; i++) if(optionptr[i] != 0x00) i += optionptr[i + 1] + 2 -1;
  230. return i;
  231. }
  232. // calculates checksum for dhcp messages.
  233. static uint16_t dhcp_checksum(void *addr, int count)
  234. {
  235. int32_t sum = 0;
  236. uint16_t tmp = 0, *source = (uint16_t *)addr;
  237. while (count > 1) {
  238. sum += *source++;
  239. count -= 2;
  240. }
  241. if (count > 0) {
  242. *(uint8_t*)&tmp = *(uint8_t*)source;
  243. sum += tmp;
  244. }
  245. while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16);
  246. return ~sum;
  247. }
  248. // gets information of INTERFACE and updates IFINDEX, MAC and IP
  249. static int get_interface( char *interface, int *ifindex, uint32_t *oip, uint8_t *mac)
  250. {
  251. struct ifreq req;
  252. struct sockaddr_in *ip;
  253. int fd = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW);
  254. req.ifr_addr.sa_family = AF_INET;
  255. xstrncpy(req.ifr_name, interface, IFNAMSIZ);
  256. req.ifr_name[IFNAMSIZ-1] = '\0';
  257. xioctl(fd, SIOCGIFFLAGS, &req);
  258. if (!(req.ifr_flags & IFF_UP)) return -1;
  259. if (oip) {
  260. xioctl(fd, SIOCGIFADDR, &req);
  261. ip = (struct sockaddr_in*) &req.ifr_addr;
  262. dbg("IP %s\n", inet_ntoa(ip->sin_addr));
  263. *oip = ntohl(ip->sin_addr.s_addr);
  264. }
  265. if (ifindex) {
  266. xioctl(fd, SIOCGIFINDEX, &req);
  267. dbg("Adapter index %d\n", req.ifr_ifindex);
  268. *ifindex = req.ifr_ifindex;
  269. }
  270. if (mac) {
  271. xioctl(fd, SIOCGIFHWADDR, &req);
  272. memcpy(mac, req.ifr_hwaddr.sa_data, 6);
  273. dbg("MAC %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  274. }
  275. close(fd);
  276. return 0;
  277. }
  278. /*
  279. *logs messeges to syslog or console
  280. *opening the log is still left with applet.
  281. *FIXME: move to more relevent lib. probably libc.c
  282. */
  283. static void infomsg(uint8_t infomode, char *s, ...)
  284. {
  285. int used;
  286. char *msg;
  287. va_list p, t;
  288. if (infomode == LOG_SILENT) return;
  289. va_start(p, s);
  290. va_copy(t, p);
  291. used = vsnprintf(NULL, 0, s, t);
  292. used++;
  293. va_end(t);
  294. msg = xmalloc(used);
  295. vsnprintf(msg, used, s, p);
  296. va_end(p);
  297. if (infomode & LOG_SYSTEM) syslog(LOG_INFO, "%s", msg);
  298. if (infomode & LOG_CONSOLE) printf("%s\n", msg);
  299. free(msg);
  300. }
  301. /*
  302. * Writes self PID in file PATH
  303. * FIXME: libc implementation only writes in /var/run
  304. * this is more generic as some implemenation may provide
  305. * arguments to write in specific file. as dhcpd does.
  306. */
  307. static void write_pid(char *path)
  308. {
  309. int pidfile = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0666);
  310. if (pidfile > 0) {
  311. char pidbuf[12];
  312. sprintf(pidbuf, "%u", (unsigned)getpid());
  313. write(pidfile, pidbuf, strlen(pidbuf));
  314. close(pidfile);
  315. }
  316. }
  317. // String STR to UINT32 conversion strored in VAR
  318. static long strtou32( char *str)
  319. {
  320. char *endptr = NULL;
  321. int base = 10;
  322. errno=0;
  323. if (str[0]=='0' && (str[1]=='x' || str[1]=='X')) {
  324. base = 16;
  325. str+=2;
  326. }
  327. long ret_val = strtol(str, &endptr, base);
  328. if (errno) return -1;
  329. else if (endptr && (*endptr!='\0'||endptr == str)) return -1;
  330. return ret_val;
  331. }
  332. // IP String STR to binary data.
  333. static int striptovar( char *str, void *var)
  334. {
  335. in_addr_t addr;
  336. if(!str) error_exit("NULL address string.");
  337. addr = inet_addr(str);
  338. if(addr == -1) error_exit("Wrong address %s.",str );
  339. *((uint32_t*)(var)) = (uint32_t)addr;
  340. return 0;
  341. }
  342. // String to dhcp option conversion
  343. static int strtoopt( char *str, uint8_t optonly)
  344. {
  345. char *option, *valstr, *grp, *tp;
  346. long optcode = 0, convtmp;
  347. uint16_t flag = 0;
  348. uint32_t mask, nip, router;
  349. int count, size = ARRAY_LEN(options_list);
  350. if (!*str) return 0;
  351. option = strtok((char*)str, ":");
  352. if (!option) return -1;
  353. dbg("-x option : %s ", option);
  354. optcode = strtou32(option);
  355. if (optcode > 0 && optcode < 256) { // raw option
  356. for (count = 0; count < size; count++) {
  357. if ((options_list[count].code & 0X00FF) == optcode) {
  358. flag = (options_list[count].code & 0XFF00);
  359. break;
  360. }
  361. }
  362. if (count == size) error_exit("Obsolete OR Unknown Option : %s", option);
  363. } else { // string option
  364. for (count = 0; count < size; count++) {
  365. if (!strcmp(options_list[count].key, option)) {
  366. flag = (options_list[count].code & 0XFF00);
  367. optcode = (options_list[count].code & 0X00FF);
  368. break;
  369. }
  370. }
  371. if (count == size) error_exit("Obsolete OR Unknown Option : %s", option);
  372. }
  373. if (!flag || !optcode) return -1;
  374. if (optonly) return optcode;
  375. valstr = strtok(NULL, "\n");
  376. if (!valstr) error_exit("option %s has no value defined.\n", option);
  377. dbg(" value : %-20s \n ", valstr);
  378. switch (flag) {
  379. case DHCP_NUM32:
  380. options_list[count].len = sizeof(uint32_t);
  381. options_list[count].val = xmalloc(sizeof(uint32_t));
  382. convtmp = strtou32(valstr);
  383. if (convtmp < 0) error_exit("Invalid/wrong formatted number %s", valstr);
  384. convtmp = htonl(convtmp);
  385. memcpy(options_list[count].val, &convtmp, sizeof(uint32_t));
  386. break;
  387. case DHCP_NUM16:
  388. options_list[count].len = sizeof(uint16_t);
  389. options_list[count].val = xmalloc(sizeof(uint16_t));
  390. convtmp = strtou32(valstr);
  391. if (convtmp < 0) error_exit("Invalid/malformed number %s", valstr);
  392. convtmp = htons(convtmp);
  393. memcpy(options_list[count].val, &convtmp, sizeof(uint16_t));
  394. break;
  395. case DHCP_NUM8:
  396. options_list[count].len = sizeof(uint8_t);
  397. options_list[count].val = xmalloc(sizeof(uint8_t));
  398. convtmp = strtou32(valstr);
  399. if (convtmp < 0) error_exit("Invalid/malformed number %s", valstr);
  400. memcpy(options_list[count].val, &convtmp, sizeof(uint8_t));
  401. break;
  402. case DHCP_IP:
  403. options_list[count].len = sizeof(uint32_t);
  404. options_list[count].val = xmalloc(sizeof(uint32_t));
  405. striptovar(valstr, options_list[count].val);
  406. break;
  407. case DHCP_STRING:
  408. options_list[count].len = strlen(valstr);
  409. options_list[count].val = strdup(valstr);
  410. break;
  411. case DHCP_IPLIST:
  412. while(valstr){
  413. options_list[count].val = xrealloc(options_list[count].val, options_list[count].len + sizeof(uint32_t));
  414. striptovar(valstr, ((uint8_t*)options_list[count].val)+options_list[count].len);
  415. options_list[count].len += sizeof(uint32_t);
  416. valstr = strtok(NULL," \t");
  417. }
  418. break;
  419. case DHCP_STRLST:
  420. case DHCP_IPPLST:
  421. break;
  422. case DHCP_STCRTS:
  423. /* Option binary format:
  424. * mask [one byte, 0..32]
  425. * ip [0..4 bytes depending on mask]
  426. * router [4 bytes]
  427. * may be repeated
  428. * staticroutes 10.0.0.0/8 10.127.0.1, 10.11.12.0/24 10.11.12.1
  429. */
  430. grp = strtok(valstr, ",");;
  431. while(grp){
  432. while(*grp == ' ' || *grp == '\t') grp++;
  433. tp = strchr(grp, '/');
  434. if (!tp) error_exit("malformed static route option");
  435. *tp = '\0';
  436. mask = strtol(++tp, &tp, 10);
  437. if (striptovar(grp, (uint8_t*)&nip) < 0) error_exit("malformed static route option");
  438. while(*tp == ' ' || *tp == '\t' || *tp == '-') tp++;
  439. if (striptovar(tp, (uint8_t*)&router) < 0) error_exit("malformed static route option");
  440. options_list[count].val = xrealloc(options_list[count].val, options_list[count].len + 1 + mask/8 + 4);
  441. memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &mask, 1);
  442. options_list[count].len += 1;
  443. memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &nip, mask/8);
  444. options_list[count].len += mask/8;
  445. memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &router, 4);
  446. options_list[count].len += 4;
  447. tp = NULL;
  448. grp = strtok(NULL, ",");
  449. }
  450. break;
  451. }
  452. return 0;
  453. }
  454. // Creates environment pointers from RES to use in script
  455. static int fill_envp(dhcpc_result_t *res)
  456. {
  457. struct in_addr temp;
  458. int size = ARRAY_LEN(options_list), count, ret = -1;
  459. ret = setenv("interface", state->iface, 1);
  460. if (!res) return ret;
  461. if (res->ipaddr.s_addr) {
  462. temp.s_addr = htonl(res->ipaddr.s_addr);
  463. ret = setenv("ip", inet_ntoa(temp), 1);
  464. if (ret) return ret;
  465. }
  466. if (msgopt_list) {
  467. for (count = 0; count < size; count++) {
  468. if ((msgopt_list[count].len == 0) || (msgopt_list[count].val == NULL)) continue;
  469. ret = setenv(msgopt_list[count].key, (char*)msgopt_list[count].val, 1);
  470. if (ret) return ret;
  471. }
  472. }
  473. return ret;
  474. }
  475. // Executes Script NAME.
  476. static void run_script(dhcpc_result_t *res, char *name)
  477. {
  478. volatile int error = 0;
  479. pid_t pid;
  480. char *argv[3];
  481. struct stat sts;
  482. char *script = (toys.optflags & FLAG_s) ? TT.script
  483. : "/usr/share/dhcp/default.script";
  484. if (stat(script, &sts) == -1 && errno == ENOENT) return;
  485. if (fill_envp(res)) {
  486. dbg("Failed to create environment variables.");
  487. return;
  488. }
  489. dbg("Executing %s %s\n", script, name);
  490. argv[0] = (char*) script;
  491. argv[1] = (char*) name;
  492. argv[2] = NULL;
  493. fflush(NULL);
  494. pid = vfork();
  495. if (pid < 0) {
  496. dbg("Fork failed.\n");
  497. return;
  498. }
  499. if (!pid) {
  500. execvp(argv[0], argv);
  501. error = errno;
  502. _exit(111);
  503. }
  504. if (error) {
  505. waitpid(pid, NULL,0);
  506. errno = error;
  507. perror_msg("script exec failed");
  508. }
  509. dbg("script complete.\n");
  510. }
  511. // returns a randome ID
  512. static uint32_t getxid(void)
  513. {
  514. uint32_t randnum;
  515. int fd = xopenro("/dev/urandom");
  516. // TODO xreadfile
  517. xreadall(fd, &randnum, sizeof(randnum));
  518. xclose(fd);
  519. return randnum;
  520. }
  521. // opens socket in raw mode.
  522. static int mode_raw(void)
  523. {
  524. state->mode = MODE_OFF;
  525. struct sockaddr_ll sock;
  526. if (state->sockfd > 0) close(state->sockfd);
  527. dbg("Opening raw socket on ifindex %d\n", state->ifindex);
  528. state->sockfd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
  529. if (state->sockfd < 0) {
  530. dbg("MODE RAW : socket fail ERROR : %d\n", state->sockfd);
  531. return -1;
  532. }
  533. dbg("Got raw socket fd %d\n", state->sockfd);
  534. memset(&sock, 0, sizeof(sock));
  535. sock.sll_family = AF_PACKET;
  536. sock.sll_protocol = htons(ETH_P_IP);
  537. sock.sll_ifindex = state->ifindex;
  538. if (bind(state->sockfd, (struct sockaddr *) &sock, sizeof(sock))) {
  539. dbg("MODE RAW : bind fail.\n");
  540. close(state->sockfd);
  541. return -1;
  542. }
  543. state->mode = MODE_RAW;
  544. if (setsockopt(state->sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, sizeof(filter_prog)) < 0)
  545. dbg("MODE RAW : filter attach fail.\n");
  546. dbg("MODE RAW : success\n");
  547. return 0;
  548. }
  549. // opens UDP socket
  550. static int mode_app(void)
  551. {
  552. struct sockaddr_in addr;
  553. struct ifreq ifr;
  554. state->mode = MODE_OFF;
  555. if (state->sockfd > 0) close(state->sockfd);
  556. dbg("Opening listen socket on *:%d %s\n", DHCPC_CLIENT_PORT, state->iface);
  557. state->sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
  558. if (state->sockfd < 0) {
  559. dbg("MODE APP : socket fail ERROR: %d\n", state->sockfd);
  560. return -1;
  561. }
  562. setsockopt(state->sockfd, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set));
  563. if (setsockopt(state->sockfd, SOL_SOCKET, SO_BROADCAST, &set, sizeof(set)) == -1) {
  564. dbg("MODE APP : brodcast failed.\n");
  565. close(state->sockfd);
  566. return -1;
  567. }
  568. xstrncpy(ifr.ifr_name, state->iface, IFNAMSIZ);
  569. ifr.ifr_name[IFNAMSIZ -1] = '\0';
  570. setsockopt(state->sockfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
  571. memset(&addr, 0, sizeof(addr));
  572. addr.sin_family = AF_INET;
  573. addr.sin_port = htons(DHCPC_CLIENT_PORT);
  574. addr.sin_addr.s_addr = INADDR_ANY ;
  575. if (bind(state->sockfd, (struct sockaddr *) &addr, sizeof(addr))) {
  576. close(state->sockfd);
  577. dbg("MODE APP : bind failed.\n");
  578. return -1;
  579. }
  580. state->mode = MODE_APP;
  581. dbg("MODE APP : success\n");
  582. return 0;
  583. }
  584. static int read_raw(void)
  585. {
  586. dhcp_raw_t packet;
  587. int bytes = 0;
  588. memset(&packet, 0, sizeof(packet));
  589. if ((bytes = read(state->sockfd, &packet, sizeof(packet))) < 0) {
  590. dbg("\tPacket read error, ignoring\n");
  591. return bytes;
  592. }
  593. if (bytes < (int) (sizeof(packet.iph) + sizeof(packet.udph))) {
  594. dbg("\tPacket is too short, ignoring\n");
  595. return -2;
  596. }
  597. if (bytes < ntohs(packet.iph.tot_len)) {
  598. dbg("\tOversized packet, ignoring\n");
  599. return -2;
  600. }
  601. // ignore any extra garbage bytes
  602. bytes = ntohs(packet.iph.tot_len);
  603. // make sure its the right packet for us, and that it passes sanity checks
  604. if (packet.iph.protocol != IPPROTO_UDP || packet.iph.version != IPVERSION
  605. || packet.iph.ihl != (sizeof(packet.iph) >> 2)
  606. || packet.udph.dest != htons(DHCPC_CLIENT_PORT)
  607. || ntohs(packet.udph.len) != (uint16_t)(bytes - sizeof(packet.iph))) {
  608. dbg("\tUnrelated/bogus packet, ignoring\n");
  609. return -2;
  610. }
  611. // Verify IP checksum.
  612. if (dhcp_checksum(&packet.iph, sizeof(packet.iph)) != 0) {
  613. dbg("\tBad IP header checksum, ignoring\n");
  614. return -2;
  615. }
  616. // Verify UDP checksum. From RFC 768, the UDP checksum is done over the IPv4
  617. // pseudo header, the UDP header and the UDP data. The IPv4 pseudo header
  618. // includes saddr, daddr, protocol, and UDP length. The IP header has to be
  619. // modified for this.
  620. memset(&packet.iph, 0, ((size_t) &((struct iphdr *)0)->protocol));
  621. packet.iph.check = 0;
  622. packet.iph.tot_len = packet.udph.len;
  623. if (packet.udph.check != 0 && dhcp_checksum(&packet, bytes) != 0) {
  624. dbg("\tPacket with bad UDP checksum received, ignoring\n");
  625. return -2;
  626. }
  627. memcpy(&state->pdhcp, &packet.dhcp, bytes - (sizeof(packet.iph) + sizeof(packet.udph)));
  628. if (state->pdhcp.cookie != htonl(DHCP_MAGIC)) {
  629. dbg("\tPacket with bad magic, ignoring\n");
  630. return -2;
  631. }
  632. return bytes - sizeof(packet.iph) - sizeof(packet.udph);
  633. }
  634. static int read_app(void)
  635. {
  636. int ret;
  637. memset(&state->pdhcp, 0, sizeof(dhcp_msg_t));
  638. if ((ret = read(state->sockfd, &state->pdhcp, sizeof(dhcp_msg_t))) < 0) {
  639. dbg("Packet read error, ignoring\n");
  640. return ret; /* returns -1 */
  641. }
  642. if (state->pdhcp.cookie != htonl(DHCP_MAGIC)) {
  643. dbg("Packet with bad magic, ignoring\n");
  644. return -2;
  645. }
  646. return ret;
  647. }
  648. // Sends data through raw socket.
  649. static int send_raw(void)
  650. {
  651. struct sockaddr_ll dest_sll;
  652. dhcp_raw_t packet;
  653. unsigned padding;
  654. int fd, result = -1;
  655. memset(&packet, 0, sizeof(dhcp_raw_t));
  656. memcpy(&packet.dhcp, &state->pdhcp, sizeof(dhcp_msg_t));
  657. if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
  658. dbg("SEND RAW: socket failed\n");
  659. return result;
  660. }
  661. memset(&dest_sll, 0, sizeof(dest_sll));
  662. dest_sll.sll_family = AF_PACKET;
  663. dest_sll.sll_protocol = htons(ETH_P_IP);
  664. dest_sll.sll_ifindex = state->ifindex;
  665. dest_sll.sll_halen = 6;
  666. memcpy(dest_sll.sll_addr, bmacaddr , 6);
  667. if (bind(fd, (struct sockaddr *) &dest_sll, sizeof(dest_sll)) < 0) {
  668. dbg("SEND RAW: bind failed\n");
  669. close(fd);
  670. return result;
  671. }
  672. padding = 308 - 1 - dhcp_opt_size(state->pdhcp.options);
  673. packet.iph.protocol = IPPROTO_UDP;
  674. packet.iph.saddr = INADDR_ANY;
  675. packet.iph.daddr = INADDR_BROADCAST;
  676. packet.udph.source = htons(DHCPC_CLIENT_PORT);
  677. packet.udph.dest = htons(DHCPC_SERVER_PORT);
  678. packet.udph.len = htons(sizeof(dhcp_raw_t) - sizeof(struct iphdr) - padding);
  679. packet.iph.tot_len = packet.udph.len;
  680. packet.udph.check = dhcp_checksum(&packet, sizeof(dhcp_raw_t) - padding);
  681. packet.iph.tot_len = htons(sizeof(dhcp_raw_t) - padding);
  682. packet.iph.ihl = sizeof(packet.iph) >> 2;
  683. packet.iph.version = IPVERSION;
  684. packet.iph.ttl = IPDEFTTL;
  685. packet.iph.check = dhcp_checksum(&packet.iph, sizeof(packet.iph));
  686. result = sendto(fd, &packet, sizeof(dhcp_raw_t) - padding, 0,
  687. (struct sockaddr *) &dest_sll, sizeof(dest_sll));
  688. close(fd);
  689. if (result < 0) dbg("SEND RAW: PACKET send error\n");
  690. return result;
  691. }
  692. // Sends data through UDP socket.
  693. static int send_app(void)
  694. {
  695. struct sockaddr_in cli;
  696. int fd, ret = -1;
  697. if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
  698. dbg("SEND APP: sock failed.\n");
  699. return ret;
  700. }
  701. setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set));
  702. memset(&cli, 0, sizeof(cli));
  703. cli.sin_family = AF_INET;
  704. cli.sin_port = htons(DHCPC_CLIENT_PORT);
  705. cli.sin_addr.s_addr = state->pdhcp.ciaddr;
  706. if (bind(fd, (struct sockaddr *)&cli, sizeof(cli)) == -1) {
  707. dbg("SEND APP: bind failed.\n");
  708. goto error_fd;
  709. }
  710. memset(&cli, 0, sizeof(cli));
  711. cli.sin_family = AF_INET;
  712. cli.sin_port = htons(DHCPC_SERVER_PORT);
  713. cli.sin_addr.s_addr = state->serverid.s_addr;
  714. if (connect(fd, (struct sockaddr *)&cli, sizeof(cli)) == -1) {
  715. dbg("SEND APP: connect failed.\n");
  716. goto error_fd;
  717. }
  718. int padding = 308 - 1 - dhcp_opt_size(state->pdhcp.options);
  719. if((ret = write(fd, &state->pdhcp, sizeof(dhcp_msg_t) - padding)) < 0) {
  720. dbg("SEND APP: write failed error %d\n", ret);
  721. goto error_fd;
  722. }
  723. dbg("SEND APP: write success wrote %d\n", ret);
  724. error_fd:
  725. close(fd);
  726. return ret;
  727. }
  728. // Generic signal handler real handling is done in main funcrion.
  729. static void signal_handler(int sig)
  730. {
  731. unsigned char ch = sig;
  732. if (write(sigfd.wr, &ch, 1) != 1) dbg("can't send signal\n");
  733. }
  734. // signal setup for SIGUSR1 SIGUSR2 SIGTERM
  735. static int setup_signal()
  736. {
  737. if (pipe((int *)&sigfd) < 0) {
  738. dbg("signal pipe failed\n");
  739. return -1;
  740. }
  741. fcntl(sigfd.wr , F_SETFD, FD_CLOEXEC);
  742. fcntl(sigfd.rd , F_SETFD, FD_CLOEXEC);
  743. int flags = fcntl(sigfd.wr, F_GETFL);
  744. fcntl(sigfd.wr, F_SETFL, flags | O_NONBLOCK);
  745. signal(SIGUSR1, signal_handler);
  746. signal(SIGUSR2, signal_handler);
  747. signal(SIGTERM, signal_handler);
  748. return 0;
  749. }
  750. // adds client id to dhcp packet
  751. static uint8_t *dhcpc_addclientid(uint8_t *optptr)
  752. {
  753. *optptr++ = DHCP_OPTION_CLIENTID;
  754. *optptr++ = 7;
  755. *optptr++ = 1;
  756. memcpy(optptr, &state->macaddr, 6);
  757. return optptr + 6;
  758. }
  759. // adds messege type to dhcp packet
  760. static uint8_t *dhcpc_addmsgtype(uint8_t *optptr, uint8_t type)
  761. {
  762. *optptr++ = DHCP_OPTION_MSG_TYPE;
  763. *optptr++ = 1;
  764. *optptr++ = type;
  765. return optptr;
  766. }
  767. // adds max size to dhcp packet
  768. static uint8_t *dhcpc_addmaxsize(uint8_t *optptr, uint16_t size)
  769. {
  770. *optptr++ = DHCP_OPTION_MAX_SIZE;
  771. *optptr++ = 2;
  772. memcpy(optptr, &size, 2);
  773. return optptr + 2;
  774. }
  775. static uint8_t *dhcpc_addstropt(uint8_t *optptr, uint8_t opcode, char* str, int len)
  776. {
  777. *optptr++ = opcode;
  778. *optptr++ = len;
  779. memcpy(optptr, str, len);
  780. return optptr + len;
  781. }
  782. // adds server id to dhcp packet.
  783. static uint8_t *dhcpc_addserverid(struct in_addr *serverid, uint8_t *optptr)
  784. {
  785. *optptr++ = DHCP_OPTION_SERVER_ID;
  786. *optptr++ = 4;
  787. memcpy(optptr, &serverid->s_addr, 4);
  788. return optptr + 4;
  789. }
  790. // adds requested ip address to dhcp packet.
  791. static uint8_t *dhcpc_addreqipaddr(struct in_addr *ipaddr, uint8_t *optptr)
  792. {
  793. *optptr++ = DHCP_OPTION_REQ_IPADDR;
  794. *optptr++ = 4;
  795. memcpy(optptr, &ipaddr->s_addr, 4);
  796. return optptr + 4;
  797. }
  798. // adds hostname to dhcp packet.
  799. static uint8_t *dhcpc_addfdnname(uint8_t *optptr, char *hname)
  800. {
  801. int size = strlen(hname);
  802. *optptr++ = DHCP_OPTION_FQDN;
  803. *optptr++ = size + 3;
  804. *optptr++ = 0x1; //flags
  805. optptr += 2; // two blank bytes
  806. strcpy((char*)optptr, hname); // name
  807. return optptr + size;
  808. }
  809. // adds request options using -o,-O flag to dhcp packet
  810. static uint8_t *dhcpc_addreqoptions(uint8_t *optptr)
  811. {
  812. uint8_t *len;
  813. *optptr++ = DHCP_OPTION_REQ_LIST;
  814. len = optptr;
  815. *len = 0;
  816. optptr++;
  817. if (!(toys.optflags & FLAG_o)) {
  818. *len = 4;
  819. *optptr++ = DHCP_OPTION_SUBNET_MASK;
  820. *optptr++ = DHCP_OPTION_ROUTER;
  821. *optptr++ = DHCP_OPTION_DNS_SERVER;
  822. *optptr++ = DHCP_OPTION_BROADCAST;
  823. }
  824. if (toys.optflags & FLAG_O) {
  825. memcpy(optptr++, raw_opt, raw_optcount);
  826. *len += raw_optcount;
  827. }
  828. return optptr;
  829. }
  830. static uint8_t *dhcpc_addend(uint8_t *optptr)
  831. {
  832. *optptr++ = DHCP_OPTION_END;
  833. return optptr;
  834. }
  835. // Sets values of -x options in dhcp discover and request packet.
  836. static uint8_t* set_xopt(uint8_t *optptr)
  837. {
  838. int count;
  839. int size = ARRAY_LEN(options_list);
  840. for (count = 0; count < size; count++) {
  841. if ((options_list[count].len == 0) || (options_list[count].val == NULL)) continue;
  842. *optptr++ = (uint8_t) (options_list[count].code & 0x00FF);
  843. *optptr++ = (uint8_t) options_list[count].len;
  844. memcpy(optptr, options_list[count].val, options_list[count].len);
  845. optptr += options_list[count].len;
  846. }
  847. return optptr;
  848. }
  849. static uint32_t get_option_serverid (uint8_t *opt, dhcpc_result_t *presult)
  850. {
  851. uint32_t var = 0;
  852. while (*opt != DHCP_OPTION_SERVER_ID) {
  853. if (*opt == DHCP_OPTION_END) return var;
  854. opt += opt[1] + 2;
  855. }
  856. memcpy(&var, opt+2, sizeof(uint32_t));
  857. state->serverid.s_addr = var;
  858. presult->serverid.s_addr = state->serverid.s_addr;
  859. presult->serverid.s_addr = ntohl(presult->serverid.s_addr);
  860. return var;
  861. }
  862. static uint8_t get_option_msgtype(uint8_t *opt)
  863. {
  864. uint32_t var = 0;
  865. while (*opt != DHCP_OPTION_MSG_TYPE) {
  866. if (*opt == DHCP_OPTION_END) return var;
  867. opt += opt[1] + 2;
  868. }
  869. memcpy(&var, opt+2, sizeof(uint8_t));
  870. return var;
  871. }
  872. static uint8_t get_option_lease(uint8_t *opt, dhcpc_result_t *presult)
  873. {
  874. uint32_t var = 0;
  875. while (*opt != DHCP_OPTION_LEASE_TIME) {
  876. if (*opt == DHCP_OPTION_END) return var;
  877. opt += opt[1] + 2;
  878. }
  879. memcpy(&var, opt+2, sizeof(uint32_t));
  880. var = htonl(var);
  881. presult->lease_time = var;
  882. return var;
  883. }
  884. // sends dhcp msg of MSGTYPE
  885. static int dhcpc_sendmsg(int msgtype)
  886. {
  887. uint8_t *pend;
  888. struct in_addr rqsd;
  889. char *vendor;
  890. // Create the common message header settings
  891. memset(&state->pdhcp, 0, sizeof(dhcp_msg_t));
  892. state->pdhcp.op = DHCP_REQUEST;
  893. state->pdhcp.htype = DHCP_HTYPE_ETHERNET;
  894. state->pdhcp.hlen = 6;
  895. state->pdhcp.xid = xid;
  896. memcpy(state->pdhcp.chaddr, state->macaddr, 6);
  897. memset(&state->pdhcp.chaddr[6], 0, 10);
  898. state->pdhcp.cookie = htonl(DHCP_MAGIC);;
  899. // Add the common header options
  900. pend = state->pdhcp.options;
  901. pend = dhcpc_addmsgtype(pend, msgtype);
  902. if (!(toys.optflags & FLAG_C)) pend = dhcpc_addclientid(pend);
  903. // Handle the message specific settings
  904. switch (msgtype) {
  905. case DHCPDISCOVER: // Broadcast DISCOVER message to all servers
  906. state->pdhcp.flags = htons(BOOTP_BROADCAST); // Broadcast bit.
  907. if (toys.optflags & FLAG_r) {
  908. inet_aton(TT.req_ip, &rqsd);
  909. pend = dhcpc_addreqipaddr(&rqsd, pend);
  910. }
  911. pend = dhcpc_addmaxsize(pend, htons(sizeof(dhcp_raw_t)));
  912. vendor = (toys.optflags & FLAG_V) ? TT.vendor_cls : "toybox\0";
  913. pend = dhcpc_addstropt(pend, DHCP_OPTION_VENDOR, vendor, strlen(vendor));
  914. if (toys.optflags & FLAG_H) pend = dhcpc_addstropt(pend, DHCP_OPTION_HOST_NAME, TT.hostname, strlen(TT.hostname));
  915. if (toys.optflags & FLAG_F) pend = dhcpc_addfdnname(pend, TT.fdn_name);
  916. if (!(toys.optflags & FLAG_o) || (toys.optflags & FLAG_O))
  917. pend = dhcpc_addreqoptions(pend);
  918. if (toys.optflags & FLAG_x) pend = set_xopt(pend);
  919. break;
  920. case DHCPREQUEST: // Send REQUEST message to the server that sent the *first* OFFER
  921. state->pdhcp.flags = htons(BOOTP_BROADCAST); // Broadcast bit.
  922. if (state->status == STATE_RENEWING) memcpy(&state->pdhcp.ciaddr, &state->ipaddr.s_addr, 4);
  923. pend = dhcpc_addmaxsize(pend, htons(sizeof(dhcp_raw_t)));
  924. rqsd.s_addr = htonl(server);
  925. pend = dhcpc_addserverid(&rqsd, pend);
  926. pend = dhcpc_addreqipaddr(&state->ipaddr, pend);
  927. vendor = (toys.optflags & FLAG_V) ? TT.vendor_cls : "toybox\0";
  928. pend = dhcpc_addstropt(pend, DHCP_OPTION_VENDOR, vendor, strlen(vendor));
  929. if (toys.optflags & FLAG_H) pend = dhcpc_addstropt(pend, DHCP_OPTION_HOST_NAME, TT.hostname, strlen(TT.hostname));
  930. if (toys.optflags & FLAG_F) pend = dhcpc_addfdnname(pend, TT.fdn_name);
  931. if (!(toys.optflags & FLAG_o) || (toys.optflags & FLAG_O))
  932. pend = dhcpc_addreqoptions(pend);
  933. if (toys.optflags & FLAG_x) pend = set_xopt(pend);
  934. break;
  935. case DHCPRELEASE: // Send RELEASE message to the server.
  936. memcpy(&state->pdhcp.ciaddr, &state->ipaddr.s_addr, 4);
  937. rqsd.s_addr = htonl(server);
  938. pend = dhcpc_addserverid(&rqsd, pend);
  939. break;
  940. default:
  941. return -1;
  942. }
  943. pend = dhcpc_addend(pend);
  944. if (state->mode == MODE_APP) return send_app();
  945. return send_raw();
  946. }
  947. /*
  948. * parses options from received dhcp packet at OPTPTR and
  949. * stores result in PRESULT or MSGOPT_LIST
  950. */
  951. static uint8_t dhcpc_parseoptions(dhcpc_result_t *presult, uint8_t *optptr)
  952. {
  953. uint8_t type = 0, *options, overloaded = 0;;
  954. uint16_t flag = 0;
  955. uint32_t convtmp = 0;
  956. char *dest, *pfx;
  957. struct in_addr addr;
  958. int count, optlen, size = ARRAY_LEN(options_list);
  959. if (toys.optflags & FLAG_x) {
  960. if(msgopt_list){
  961. for (count = 0; count < size; count++){
  962. if(msgopt_list[count].val) free(msgopt_list[count].val);
  963. msgopt_list[count].val = NULL;
  964. msgopt_list[count].len = 0;
  965. }
  966. } else {
  967. msgopt_list = xmalloc(sizeof(options_list));
  968. memcpy(msgopt_list, options_list, sizeof(options_list));
  969. for (count = 0; count < size; count++) {
  970. msgopt_list[count].len = 0;
  971. msgopt_list[count].val = NULL;
  972. }
  973. }
  974. } else {
  975. msgopt_list = options_list;
  976. for (count = 0; count < size; count++) {
  977. msgopt_list[count].len = 0;
  978. if(msgopt_list[count].val) free(msgopt_list[count].val);
  979. msgopt_list[count].val = NULL;
  980. }
  981. }
  982. while (*optptr != DHCP_OPTION_END) {
  983. if (*optptr == DHCP_OPTION_PADDING) {
  984. optptr++;
  985. continue;
  986. }
  987. if (*optptr == DHCP_OPTION_OVERLOAD) {
  988. overloaded = optptr[2];
  989. optptr += optptr[1] + 2;
  990. continue;
  991. }
  992. for (count = 0, flag = 0; count < size; count++) {
  993. if ((msgopt_list[count].code & 0X00FF) == *optptr) {
  994. flag = (msgopt_list[count].code & 0XFF00);
  995. break;
  996. }
  997. }
  998. switch (flag) {
  999. case DHCP_NUM32:
  1000. memcpy(&convtmp, &optptr[2], sizeof(uint32_t));
  1001. convtmp = htonl(convtmp);
  1002. sprintf(toybuf, "%u", convtmp);
  1003. msgopt_list[count].val = strdup(toybuf);
  1004. msgopt_list[count].len = strlen(toybuf);
  1005. break;
  1006. case DHCP_NUM16:
  1007. memcpy(&convtmp, &optptr[2], sizeof(uint16_t));
  1008. convtmp = htons(convtmp);
  1009. sprintf(toybuf, "%u", convtmp);
  1010. msgopt_list[count].val = strdup(toybuf);
  1011. msgopt_list[count].len = strlen(toybuf);
  1012. break;
  1013. case DHCP_NUM8:
  1014. memcpy(&convtmp, &optptr[2], sizeof(uint8_t));
  1015. sprintf(toybuf, "%u", convtmp);
  1016. msgopt_list[count].val = strdup(toybuf);
  1017. msgopt_list[count].len = strlen(toybuf);
  1018. break;
  1019. case DHCP_IP:
  1020. memcpy(&convtmp, &optptr[2], sizeof(uint32_t));
  1021. addr.s_addr = convtmp;
  1022. sprintf(toybuf, "%s", inet_ntoa(addr));
  1023. msgopt_list[count].val = strdup(toybuf);
  1024. msgopt_list[count].len = strlen(toybuf);
  1025. break;
  1026. case DHCP_STRING:
  1027. sprintf(toybuf, "%.*s", optptr[1], &optptr[2]);
  1028. msgopt_list[count].val = strdup(toybuf);
  1029. msgopt_list[count].len = strlen(toybuf);
  1030. break;
  1031. case DHCP_IPLIST:
  1032. options = &optptr[2];
  1033. optlen = optptr[1];
  1034. dest = toybuf;
  1035. while (optlen) {
  1036. memcpy(&convtmp, options, sizeof(uint32_t));
  1037. addr.s_addr = convtmp;
  1038. dest += sprintf(dest, "%s ", inet_ntoa(addr));
  1039. options += 4;
  1040. optlen -= 4;
  1041. }
  1042. *(dest - 1) = '\0';
  1043. msgopt_list[count].val = strdup(toybuf);
  1044. msgopt_list[count].len = strlen(toybuf);
  1045. break;
  1046. case DHCP_STRLST: //FIXME: do smthing.
  1047. case DHCP_IPPLST:
  1048. break;
  1049. case DHCP_STCRTS:
  1050. pfx = "";
  1051. dest = toybuf;
  1052. options = &optptr[2];
  1053. optlen = optptr[1];
  1054. while (optlen >= 1 + 4) {
  1055. uint32_t nip = 0;
  1056. int bytes;
  1057. uint8_t *p_tmp;
  1058. unsigned mask = *options;
  1059. if (mask > 32) break;
  1060. optlen--;
  1061. p_tmp = (void*) &nip;
  1062. bytes = (mask + 7) / 8;
  1063. while (--bytes >= 0) {
  1064. *p_tmp++ = *options++;
  1065. optlen--;
  1066. }
  1067. if (optlen < 4) break;
  1068. dest += sprintf(dest, "%s%u.%u.%u.%u", pfx, ((uint8_t*) &nip)[0],
  1069. ((uint8_t*) &nip)[1], ((uint8_t*) &nip)[2], ((uint8_t*) &nip)[3]);
  1070. pfx = " ";
  1071. dest += sprintf(dest, "/%u ", mask);
  1072. dest += sprintf(dest, "%u.%u.%u.%u", options[0], options[1], options[2], options[3]);
  1073. options += 4;
  1074. optlen -= 4;
  1075. }
  1076. msgopt_list[count].val = strdup(toybuf);
  1077. msgopt_list[count].len = strlen(toybuf);
  1078. break;
  1079. default: break;
  1080. }
  1081. optptr += optptr[1] + 2;
  1082. }
  1083. if ((overloaded == 1) || (overloaded == 3)) dhcpc_parseoptions(presult, optptr);
  1084. if ((overloaded == 2) || (overloaded == 3)) dhcpc_parseoptions(presult, optptr);
  1085. return type;
  1086. }
  1087. // parses recvd messege to check that it was for us.
  1088. static uint8_t dhcpc_parsemsg(dhcpc_result_t *presult)
  1089. {
  1090. if (state->pdhcp.op == DHCP_REPLY
  1091. && !memcmp(state->pdhcp.chaddr, state->macaddr, 6)
  1092. && !memcmp(&state->pdhcp.xid, &xid, sizeof(xid))) {
  1093. memcpy(&presult->ipaddr.s_addr, &state->pdhcp.yiaddr, 4);
  1094. presult->ipaddr.s_addr = ntohl(presult->ipaddr.s_addr);
  1095. return get_option_msgtype(state->pdhcp.options);
  1096. }
  1097. return 0;
  1098. }
  1099. // Sends a IP renew request.
  1100. static void renew(void)
  1101. {
  1102. infomsg(infomode, "Performing a DHCP renew");
  1103. switch (state->status) {
  1104. case STATE_INIT:
  1105. break;
  1106. case STATE_BOUND:
  1107. mode_raw();
  1108. case STATE_RENEWING: // FALLTHROUGH
  1109. case STATE_REBINDING: // FALLTHROUGH
  1110. state->status = STATE_RENEW_REQUESTED;
  1111. break;
  1112. case STATE_RENEW_REQUESTED:
  1113. run_script(NULL, "deconfig");
  1114. case STATE_REQUESTING: // FALLTHROUGH
  1115. case STATE_RELEASED: // FALLTHROUGH
  1116. mode_raw();
  1117. state->status = STATE_INIT;
  1118. break;
  1119. default: break;
  1120. }
  1121. }
  1122. // Sends a IP release request.
  1123. static void release(void)
  1124. {
  1125. char buffer[sizeof("255.255.255.255\0")];
  1126. struct in_addr temp_addr;
  1127. mode_app();
  1128. // send release packet
  1129. if (state->status == STATE_BOUND || state->status == STATE_RENEWING || state->status == STATE_REBINDING) {
  1130. temp_addr.s_addr = htonl(server);
  1131. xstrncpy(buffer, inet_ntoa(temp_addr), sizeof(buffer));
  1132. temp_addr.s_addr = state->ipaddr.s_addr;
  1133. infomsg( infomode, "Unicasting a release of %s to %s", inet_ntoa(temp_addr), buffer);
  1134. dhcpc_sendmsg(DHCPRELEASE);
  1135. run_script(NULL, "deconfig");
  1136. }
  1137. infomsg(infomode, "Entering released state");
  1138. close(state->sockfd);
  1139. state->sockfd = -1;
  1140. state->mode = MODE_OFF;
  1141. state->status = STATE_RELEASED;
  1142. }
  1143. static void free_option_stores(void)
  1144. {
  1145. int count, size = ARRAY_LEN(options_list);
  1146. for (count = 0; count < size; count++)
  1147. if (options_list[count].val) free(options_list[count].val);
  1148. if (toys.optflags & FLAG_x) {
  1149. for (count = 0; count < size; count++)
  1150. if (msgopt_list[count].val) free(msgopt_list[count].val);
  1151. free(msgopt_list);
  1152. }
  1153. }
  1154. void dhcp_main(void)
  1155. {
  1156. struct timeval tv;
  1157. int retval, bufflen = 0;
  1158. dhcpc_result_t result;
  1159. uint8_t packets = 0, retries = 0;
  1160. uint32_t timeout = 0, waited = 0;
  1161. fd_set rfds;
  1162. xid = 0;
  1163. setlinebuf(stdout);
  1164. dbg = dummy;
  1165. if (toys.optflags & FLAG_v) dbg = xprintf;
  1166. if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
  1167. retries = TT.retries;
  1168. if (toys.optflags & FLAG_S) {
  1169. openlog("UDHCPC :", LOG_PID, LOG_DAEMON);
  1170. infomode |= LOG_SYSTEM;
  1171. }
  1172. infomsg(infomode, "dhcp started");
  1173. if (toys.optflags & FLAG_O) {
  1174. while (TT.req_opt) {
  1175. raw_opt[raw_optcount] = (uint8_t) strtoopt(TT.req_opt->arg, 1);
  1176. raw_optcount++;
  1177. TT.req_opt = TT.req_opt->next;
  1178. }
  1179. }
  1180. if (toys.optflags & FLAG_x) {
  1181. while (TT.pkt_opt) {
  1182. (void) strtoopt(TT.pkt_opt->arg, 0);
  1183. TT.pkt_opt = TT.pkt_opt->next;
  1184. }
  1185. }
  1186. memset(&result, 0, sizeof(dhcpc_result_t));
  1187. state = (dhcpc_state_t*) xmalloc(sizeof(dhcpc_state_t));
  1188. memset(state, 0, sizeof(dhcpc_state_t));
  1189. state->iface = (toys.optflags & FLAG_i) ? TT.iface : "eth0";
  1190. if (get_interface(state->iface, &state->ifindex, NULL, state->macaddr))
  1191. perror_exit("Failed to get interface %s", state->iface);
  1192. run_script(NULL, "deconfig");
  1193. setup_signal();
  1194. state->status = STATE_INIT;
  1195. mode_raw();
  1196. fcntl(state->sockfd, F_SETFD, FD_CLOEXEC);
  1197. for (;;) {
  1198. FD_ZERO(&rfds);
  1199. if (state->sockfd >= 0) FD_SET(state->sockfd, &rfds);
  1200. FD_SET(sigfd.rd, &rfds);
  1201. tv.tv_sec = timeout - waited;
  1202. tv.tv_usec = 0;
  1203. retval = 0;
  1204. int maxfd = (sigfd.rd > state->sockfd)? sigfd.rd : state->sockfd;
  1205. dbg("select wait ....\n");
  1206. uint32_t timestmp = time(NULL);
  1207. if((retval = select(maxfd + 1, &rfds, NULL, NULL, &tv)) < 0) {
  1208. if (errno == EINTR) {
  1209. waited += (unsigned) time(NULL) - timestmp;
  1210. continue;
  1211. }
  1212. perror_exit("Error in select");
  1213. }
  1214. if (!retval) { // Timed out
  1215. if (get_interface(state->iface, &state->ifindex, NULL, state->macaddr))
  1216. error_exit("Interface lost %s\n", state->iface);
  1217. switch (state->status) {
  1218. case STATE_INIT:
  1219. if (packets < retries) {
  1220. if (!packets) xid = getxid();
  1221. run_script(NULL, "deconfig");
  1222. infomsg(infomode, "Sending discover...");
  1223. dhcpc_sendmsg(DHCPDISCOVER);
  1224. server = 0;
  1225. timeout = TT.timeout;
  1226. waited = 0;
  1227. packets++;
  1228. continue;
  1229. }
  1230. lease_fail:
  1231. run_script(NULL,"leasefail");
  1232. if (toys.optflags & FLAG_n) {
  1233. infomsg(infomode, "Lease failed. Exiting");
  1234. goto ret_with_sockfd;
  1235. }
  1236. if (toys.optflags & FLAG_b) {
  1237. infomsg(infomode, "Lease failed. Going Daemon mode");
  1238. daemon(0, 0);
  1239. if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
  1240. toys.optflags &= ~FLAG_b;
  1241. toys.optflags |= FLAG_f;
  1242. }
  1243. timeout = TT.tryagain;
  1244. waited = 0;
  1245. packets = 0;
  1246. continue;
  1247. case STATE_REQUESTING:
  1248. if (packets < retries) {
  1249. memcpy(&state->ipaddr.s_addr,&state->pdhcp.yiaddr, 4);
  1250. dhcpc_sendmsg(DHCPREQUEST);
  1251. infomsg(infomode, "Sending select for %d.%d.%d.%d...",
  1252. (result.ipaddr.s_addr >> 24) & 0xff, (result.ipaddr.s_addr >> 16) & 0xff, (result.ipaddr.s_addr >> 8) & 0xff, (result.ipaddr.s_addr) & 0xff);
  1253. timeout = TT.timeout;
  1254. waited = 0;
  1255. packets++;
  1256. continue;
  1257. }
  1258. mode_raw();
  1259. state->status = STATE_INIT;
  1260. goto lease_fail;
  1261. case STATE_BOUND:
  1262. state->status = STATE_RENEWING;
  1263. dbg("Entering renew state\n");
  1264. // FALLTHROUGH
  1265. case STATE_RENEW_REQUESTED: // FALLTHROUGH
  1266. case STATE_RENEWING:
  1267. renew_requested:
  1268. if (timeout > 60) {
  1269. dhcpc_sendmsg(DHCPREQUEST);
  1270. timeout >>= 1;
  1271. waited = 0;
  1272. continue;
  1273. }
  1274. dbg("Entering rebinding state\n");
  1275. state->status = STATE_REBINDING;
  1276. // FALLTHROUGH
  1277. case STATE_REBINDING:
  1278. mode_raw();
  1279. if (timeout > 0) {
  1280. dhcpc_sendmsg(DHCPREQUEST);
  1281. timeout >>= 1;
  1282. waited = 0;
  1283. continue;
  1284. }
  1285. infomsg(infomode, "Lease lost, entering INIT state");
  1286. run_script(NULL, "deconfig");
  1287. state->status = STATE_INIT;
  1288. timeout = 0;
  1289. waited = 0;
  1290. packets = 0;
  1291. continue;
  1292. default: break;
  1293. }
  1294. timeout = INT_MAX;
  1295. waited = 0;
  1296. continue;
  1297. }
  1298. if (FD_ISSET(sigfd.rd, &rfds)) { // Some Activity on RDFDs : is signal
  1299. unsigned char sig;
  1300. if (read(sigfd.rd, &sig, 1) != 1) {
  1301. dbg("signal read failed.\n");
  1302. continue;
  1303. }
  1304. switch (sig) {
  1305. case SIGUSR1:
  1306. infomsg(infomode, "Received SIGUSR1");
  1307. renew();
  1308. packets = 0;
  1309. waited = 0;
  1310. if (state->status == STATE_RENEW_REQUESTED) goto renew_requested;
  1311. if (state->status == STATE_INIT) timeout = 0;
  1312. continue;
  1313. case SIGUSR2:
  1314. infomsg(infomode, "Received SIGUSR2");
  1315. release();
  1316. timeout = INT_MAX;
  1317. waited = 0;
  1318. packets = 0;
  1319. continue;
  1320. case SIGTERM:
  1321. infomsg(infomode, "Received SIGTERM");
  1322. if (toys.optflags & FLAG_R) release();
  1323. goto ret_with_sockfd;
  1324. default: break;
  1325. }
  1326. }
  1327. if (FD_ISSET(state->sockfd, &rfds)) { // Some Activity on RDFDs : is socket
  1328. dbg("main sock read\n");
  1329. uint8_t msgType;
  1330. if (state->mode == MODE_RAW) bufflen = read_raw();
  1331. if (state->mode == MODE_APP) bufflen = read_app();
  1332. if (bufflen < 0) {
  1333. if (state->mode == MODE_RAW) mode_raw();
  1334. if (state->mode == MODE_APP) mode_app();
  1335. continue;
  1336. }
  1337. waited += time(NULL) - timestmp;
  1338. memset(&result, 0, sizeof(dhcpc_result_t));
  1339. msgType = dhcpc_parsemsg(&result);
  1340. if (msgType != DHCPNAK && result.ipaddr.s_addr == 0 ) continue; // no ip for me ignore
  1341. if (!msgType || !get_option_serverid(state->pdhcp.options, &result)) continue; //no server id ignore
  1342. if (msgType == DHCPOFFER && server == 0) server = result.serverid.s_addr; // select the server
  1343. if (result.serverid.s_addr != server) continue; // not from the server we requested ignore
  1344. dhcpc_parseoptions(&result, state->pdhcp.options);
  1345. get_option_lease(state->pdhcp.options, &result);
  1346. switch (state->status) {
  1347. case STATE_INIT:
  1348. if (msgType == DHCPOFFER) {
  1349. state->status = STATE_REQUESTING;
  1350. mode_raw();
  1351. timeout = 0;
  1352. waited = 0;
  1353. packets = 0;
  1354. }
  1355. continue;
  1356. case STATE_REQUESTING: // FALLTHROUGH
  1357. case STATE_RENEWING: // FALLTHROUGH
  1358. case STATE_RENEW_REQUESTED: // FALLTHROUGH
  1359. case STATE_REBINDING:
  1360. if (msgType == DHCPACK) {
  1361. timeout = result.lease_time / 2;
  1362. run_script(&result, state->status == STATE_REQUESTING ? "bound" : "renew");
  1363. state->status = STATE_BOUND;
  1364. infomsg(infomode, "Lease of %d.%d.%d.%d obtained, lease time %d from server %d.%d.%d.%d",
  1365. (result.ipaddr.s_addr >> 24) & 0xff, (result.ipaddr.s_addr >> 16) & 0xff, (result.ipaddr.s_addr >> 8) & 0xff, (result.ipaddr.s_addr) & 0xff,
  1366. result.lease_time,
  1367. (result.serverid.s_addr >> 24) & 0xff, (result.serverid.s_addr >> 16) & 0xff, (result.serverid.s_addr >> 8) & 0xff, (result.serverid.s_addr) & 0xff);
  1368. if (toys.optflags & FLAG_q) {
  1369. if (toys.optflags & FLAG_R) release();
  1370. goto ret_with_sockfd;
  1371. }
  1372. toys.optflags &= ~FLAG_n;
  1373. if (!(toys.optflags & FLAG_f)) {
  1374. daemon(0, 0);
  1375. toys.optflags |= FLAG_f;
  1376. if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
  1377. }
  1378. waited = 0;
  1379. continue;
  1380. } else if (msgType == DHCPNAK) {
  1381. dbg("NACK received.\n");
  1382. run_script(&result, "nak");
  1383. if (state->status != STATE_REQUESTING) run_script(NULL, "deconfig");
  1384. mode_raw();
  1385. sleep(3);
  1386. state->status = STATE_INIT;
  1387. state->ipaddr.s_addr = 0;
  1388. server = 0;
  1389. timeout = 0;
  1390. packets = 0;
  1391. waited = 0;
  1392. }
  1393. continue;
  1394. default: break;
  1395. }
  1396. }
  1397. }
  1398. ret_with_sockfd:
  1399. if (CFG_TOYBOX_FREE) {
  1400. free_option_stores();
  1401. if (state->sockfd > 0) close(state->sockfd);
  1402. free(state);
  1403. }
  1404. }