1 /*
2 * DHCP library functions.
3 * Copyright (C) 2003, 2004, 2005, 2006 Mondru AB.
4 * Copyright (c) 2006-2008 David Bird <david@coova.com>
5 *
6 * The contents of this file may be used under the terms of the GNU
7 * General Public License Version 2, provided that the above copyright
8 * notice and this permission notice is included in all copies or
9 * substantial portions of the software.
10 *
11 */
12
13 #include "system.h"
14 #include "syserr.h"
15 #include "radius.h"
16 #include "radius_wispr.h"
17 #include "radius_chillispot.h"
18 #include "redir.h"
19 #include "md5.h"
20 #include "dhcp.h"
21 #include "dns.h"
22 #include "tun.h"
23 #include "chilli.h"
24 #include "options.h"
25 #include "ippool.h"
26 #include "lookup.h"
27
28 const uint32_t DHCP_OPTION_MAGIC = 0x63825363;
29
30 #ifdef NAIVE
31 const static int paranoid = 0; /* Trust that the program has no bugs */
32 #else
33 const static int paranoid = 0; /* Check for errors which cannot happen */
34 #endif
35
36 extern time_t mainclock;
37
dhcp_state2name(int authstate)38 char *dhcp_state2name(int authstate) {
39 switch(authstate) {
40 case DHCP_AUTH_NONE: return "none";
41 case DHCP_AUTH_DROP: return "drop";
42 case DHCP_AUTH_PASS: return "pass";
43 case DHCP_AUTH_DNAT: return "dnat";
44 case DHCP_AUTH_SPLASH: return "splash";
45 default: return "unknown";
46 }
47 }
48
dhcp_list(struct dhcp_t * this,bstring s,bstring pre,bstring post,int listfmt)49 void dhcp_list(struct dhcp_t *this, bstring s, bstring pre, bstring post, int listfmt) {
50 struct dhcp_conn_t *conn = this->firstusedconn;
51 if (listfmt == LIST_JSON_FMT) {
52 bcatcstr(s, "{ \"sessions\":[");
53 }
54 while (conn) {
55 if (pre) bconcat(s, pre);
56 dhcp_print(this, s, listfmt, conn);
57 if (post) bconcat(s, post);
58 conn = conn->next;
59 }
60 if (listfmt == LIST_JSON_FMT) {
61 bcatcstr(s, "]}");
62 }
63 }
64
dhcp_print(struct dhcp_t * this,bstring s,int listfmt,struct dhcp_conn_t * conn)65 void dhcp_print(struct dhcp_t *this, bstring s, int listfmt, struct dhcp_conn_t *conn) {
66 struct app_conn_t *appconn = (struct app_conn_t *)conn->peer;
67 bstring b = bfromcstr("");
68 bstring tmp = bfromcstr("");
69
70 if (conn && conn->inuse) {
71
72 if (listfmt == LIST_JSON_FMT) {
73
74 if (conn != this->firstusedconn)
75 bcatcstr(b, ",");
76
77 bcatcstr(b, "{");
78
79 if (appconn) {
80 bcatcstr(b, "\"nasPort\":");
81 bassignformat(tmp, "%d", appconn->unit);
82 bconcat(b, tmp);
83 bcatcstr(b, ",\"clientState\":");
84 bassignformat(tmp, "%d", appconn->s_state.authenticated);
85 bconcat(b, tmp);
86 bcatcstr(b, ",\"macAddress\":\"");
87 bassignformat(tmp, "%.2X-%.2X-%.2X-%.2X-%.2X-%.2X",
88 conn->hismac[0], conn->hismac[1], conn->hismac[2],
89 conn->hismac[3], conn->hismac[4], conn->hismac[5]);
90 bconcat(b, tmp);
91 bcatcstr(b, "\",\"ipAddress\":\"");
92 bcatcstr(b, inet_ntoa(conn->hisip));
93 bcatcstr(b, "\"");
94 }
95
96 } else {
97
98 bassignformat(b, "%.2X-%.2X-%.2X-%.2X-%.2X-%.2X %s %s",
99 conn->hismac[0], conn->hismac[1], conn->hismac[2],
100 conn->hismac[3], conn->hismac[4], conn->hismac[5],
101 inet_ntoa(conn->hisip), dhcp_state2name(conn->authstate));
102
103 }
104
105 if (listfmt && this->cb_getinfo)
106 this->cb_getinfo(conn, b, listfmt);
107
108 if (listfmt == LIST_JSON_FMT)
109 bcatcstr(b, "}");
110 else
111 bcatcstr(b, "\n");
112
113 bconcat(s, b);
114 }
115
116 bdestroy(b);
117 bdestroy(tmp);
118 }
119
dhcp_release_mac(struct dhcp_t * this,uint8_t * hwaddr,int term_cause)120 void dhcp_release_mac(struct dhcp_t *this, uint8_t *hwaddr, int term_cause) {
121 struct dhcp_conn_t *conn;
122 if (!dhcp_hashget(this, &conn, hwaddr)) {
123 dhcp_freeconn(conn, term_cause);
124 }
125 }
126
dhcp_send(struct dhcp_t * this,struct _net_interface * netif,unsigned char * hismac,void * packet,size_t length)127 int dhcp_send(struct dhcp_t *this, struct _net_interface *netif,
128 unsigned char *hismac, void *packet, size_t length) {
129 #if defined(__linux__)
130 struct sockaddr_ll dest;
131
132 memset(&dest, 0, sizeof(dest));
133 dest.sll_family = AF_PACKET;
134 dest.sll_protocol = htons(netif->protocol);
135 dest.sll_ifindex = netif->ifindex;
136 dest.sll_halen = PKT_ETH_ALEN;
137 memcpy(dest.sll_addr, hismac, PKT_ETH_ALEN);
138
139 if (sendto(netif->fd, packet, length, 0, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
140 #ifdef ENETDOWN
141 if (errno == ENETDOWN) {
142 net_reopen(netif);
143 }
144 #endif
145 #ifdef ENXIO
146 if (errno == ENXIO) {
147 net_reopen(netif);
148 }
149 #endif
150 log_err(errno, "sendto(fd=%d, len=%d) failed", netif->fd, length);
151 return -1;
152 }
153 #elif defined (__FreeBSD__) || defined (__APPLE__) || defined (__OpenBSD__) || defined (__NetBSD__)
154 if (write(netif->fd, packet, length) < 0) {
155 log_err(errno, "write() failed");
156 return -1;
157 }
158 #endif
159 return 0;
160 }
161
162
163 /**
164 * dhcp_hash()
165 * Generates a 32 bit hash based on a mac address
166 **/
dhcp_hash(uint8_t * hwaddr)167 uint32_t dhcp_hash(uint8_t *hwaddr) {
168 return lookup(hwaddr, PKT_ETH_ALEN, 0);
169 }
170
171
172 /**
173 * dhcp_hashinit()
174 * Initialises hash tables
175 **/
dhcp_hashinit(struct dhcp_t * this,int listsize)176 int dhcp_hashinit(struct dhcp_t *this, int listsize) {
177 /* Determine hashlog */
178 for ((this)->hashlog = 0;
179 ((1 << (this)->hashlog) < listsize);
180 (this)->hashlog++);
181
182 /* Determine hashsize */
183 (this)->hashsize = 1 << (this)->hashlog;
184 (this)->hashmask = (this)->hashsize -1;
185
186 /* Allocate hash table */
187 if (!((this)->hash = calloc(sizeof(struct dhcp_conn_t), (this)->hashsize))){
188 /* Failed to allocate memory for hash members */
189 return -1;
190 }
191 return 0;
192 }
193
194
195 /**
196 * dhcp_hashadd()
197 * Adds a connection to the hash table
198 **/
dhcp_hashadd(struct dhcp_t * this,struct dhcp_conn_t * conn)199 int dhcp_hashadd(struct dhcp_t *this, struct dhcp_conn_t *conn) {
200 uint32_t hash;
201 struct dhcp_conn_t *p;
202 struct dhcp_conn_t *p_prev = NULL;
203
204 /* Insert into hash table */
205 hash = dhcp_hash(conn->hismac) & this->hashmask;
206 for (p = this->hash[hash]; p; p = p->nexthash)
207 p_prev = p;
208 if (!p_prev)
209 this->hash[hash] = conn;
210 else
211 p_prev->nexthash = conn;
212 return 0; /* Always OK to insert */
213 }
214
215
216 /**
217 * dhcp_hashdel()
218 * Removes a connection from the hash table
219 **/
dhcp_hashdel(struct dhcp_t * this,struct dhcp_conn_t * conn)220 int dhcp_hashdel(struct dhcp_t *this, struct dhcp_conn_t *conn) {
221 uint32_t hash;
222 struct dhcp_conn_t *p;
223 struct dhcp_conn_t *p_prev = NULL;
224
225 /* Find in hash table */
226 hash = dhcp_hash(conn->hismac) & this->hashmask;
227 for (p = this->hash[hash]; p; p = p->nexthash) {
228 if (p == conn) {
229 break;
230 }
231 p_prev = p;
232 }
233
234 if ((paranoid) && (p!= conn)) {
235 log_err(0, "Tried to delete connection not in hash table");
236 }
237
238 if (!p_prev)
239 this->hash[hash] = p->nexthash;
240 else
241 p_prev->nexthash = p->nexthash;
242
243 return 0;
244 }
245
246
247 /**
248 * dhcp_hashget()
249 * Uses the hash tables to find a connection based on the mac address.
250 * Returns -1 if not found.
251 **/
dhcp_hashget(struct dhcp_t * this,struct dhcp_conn_t ** conn,uint8_t * hwaddr)252 int dhcp_hashget(struct dhcp_t *this, struct dhcp_conn_t **conn,
253 uint8_t *hwaddr) {
254 struct dhcp_conn_t *p;
255 uint32_t hash;
256
257 /* Find in hash table */
258 hash = dhcp_hash(hwaddr) & this->hashmask;
259 for (p = this->hash[hash]; p; p = p->nexthash) {
260 if ((!memcmp(p->hismac, hwaddr, PKT_ETH_ALEN)) && (p->inuse)) {
261 *conn = p;
262 return 0;
263 }
264 }
265 *conn = NULL;
266 return -1; /* Address could not be found */
267 }
268
269
270 /**
271 * dhcp_validate()
272 * Valides reference structures of connections.
273 * Returns the number of active connections
274 **/
dhcp_validate(struct dhcp_t * this)275 int dhcp_validate(struct dhcp_t *this)
276 {
277 int used = 0;
278 int unused = 0;
279 struct dhcp_conn_t *conn;
280 struct dhcp_conn_t *hash_conn;
281
282 /* Count the number of used connections */
283 conn = this->firstusedconn;
284 while (conn) {
285
286 if (!conn->inuse) {
287 log_err(0, "Connection with inuse == 0!");
288 }
289
290 dhcp_hashget(this, &hash_conn, conn->hismac);
291
292 if (conn != hash_conn) {
293 log_err(0, "Connection could not be found by hashget!");
294 }
295
296 used ++;
297 conn = conn->next;
298 }
299
300 /* Count the number of unused connections */
301 conn = this->firstfreeconn;
302 while (conn) {
303 if (conn->inuse) {
304 log_err(0, "Connection with inuse != 0!");
305 }
306 unused ++;
307 conn = conn->next;
308 }
309
310 if (this->numconn != (used + unused)) {
311 log_err(0, "The number of free and unused connections does not match!");
312 if (this->debug) {
313 log_dbg("used %d unused %d", used, unused);
314 conn = this->firstusedconn;
315 while (conn) {
316 log_dbg("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
317 conn->hismac[0], conn->hismac[1], conn->hismac[2],
318 conn->hismac[3], conn->hismac[4], conn->hismac[5]);
319 conn = conn->next;
320 }
321 }
322 }
323
324 return used;
325 }
326
327
328 /**
329 * dhcp_initconn()
330 * Initialises connection references
331 **/
dhcp_initconn(struct dhcp_t * this)332 int dhcp_initconn(struct dhcp_t *this)
333 {
334 int n;
335 this->firstusedconn = NULL; /* Redundant */
336 this->lastusedconn = NULL; /* Redundant */
337
338 for (n=0; n<this->numconn; n++) {
339 this->conn[n].inuse = 0; /* Redundant */
340 if (n == 0) {
341 this->conn[n].prev = NULL; /* Redundant */
342 this->firstfreeconn = &this->conn[n];
343
344 }
345 else {
346 this->conn[n].prev = &this->conn[n-1];
347 this->conn[n-1].next = &this->conn[n];
348 }
349 if (n == (this->numconn-1)) {
350 this->conn[n].next = NULL; /* Redundant */
351 this->lastfreeconn = &this->conn[n];
352 }
353 }
354
355 if (paranoid) dhcp_validate(this);
356
357 return 0;
358 }
359
360 /**
361 * dhcp_newconn()
362 * Allocates a new connection from the pool.
363 * Returns -1 if unsuccessful.
364 **/
dhcp_newconn(struct dhcp_t * this,struct dhcp_conn_t ** conn,uint8_t * hwaddr)365 int dhcp_newconn(struct dhcp_t *this,
366 struct dhcp_conn_t **conn,
367 uint8_t *hwaddr)
368 {
369
370 if (this->debug)
371 log_dbg("DHCP newconn: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
372 hwaddr[0], hwaddr[1], hwaddr[2],
373 hwaddr[3], hwaddr[4], hwaddr[5]);
374
375
376 if (!this->firstfreeconn) {
377 log_err(0, "Out of free connections");
378 return -1;
379 }
380
381 *conn = this->firstfreeconn;
382
383 /* Remove from link of free */
384 if (this->firstfreeconn->next) {
385 this->firstfreeconn->next->prev = NULL;
386 this->firstfreeconn = this->firstfreeconn->next;
387 }
388 else { /* Took the last one */
389 this->firstfreeconn = NULL;
390 this->lastfreeconn = NULL;
391 }
392
393 /* Initialise structures */
394 memset(*conn, 0, sizeof(**conn));
395
396 /* Insert into link of used */
397 if (this->firstusedconn) {
398 this->firstusedconn->prev = *conn;
399 (*conn)->next = this->firstusedconn;
400 }
401 else { /* First insert */
402 this->lastusedconn = *conn;
403 }
404
405 this->firstusedconn = *conn;
406
407 (*conn)->inuse = 1;
408 (*conn)->parent = this;
409
410 /* Application specific initialisations */
411 memcpy((*conn)->hismac, hwaddr, PKT_ETH_ALEN);
412 memcpy((*conn)->ourmac, this->ipif.hwaddr, PKT_ETH_ALEN);
413 (*conn)->lasttime = mainclock;
414
415 dhcp_hashadd(this, *conn);
416
417 if (paranoid) dhcp_validate(this);
418
419 /* Inform application that connection was created */
420 if (this->cb_connect)
421 this->cb_connect(*conn);
422
423 return 0; /* Success */
424 }
425
426
427 /**
428 * dhcp_freeconn()
429 * Returns a connection to the pool.
430 **/
dhcp_freeconn(struct dhcp_conn_t * conn,int term_cause)431 int dhcp_freeconn(struct dhcp_conn_t *conn, int term_cause)
432 {
433 /* TODO: Always returns success? */
434
435 struct dhcp_t *this = conn->parent;
436
437 /* Tell application that we disconnected */
438 if (this->cb_disconnect)
439 this->cb_disconnect(conn, term_cause);
440
441 if (this->debug)
442 log_dbg("DHCP freeconn: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
443 conn->hismac[0], conn->hismac[1], conn->hismac[2],
444 conn->hismac[3], conn->hismac[4], conn->hismac[5]);
445
446
447 /* Application specific code */
448 /* First remove from hash table */
449 dhcp_hashdel(this, conn);
450
451 /* Remove from link of used */
452 if ((conn->next) && (conn->prev)) {
453 conn->next->prev = conn->prev;
454 conn->prev->next = conn->next;
455 }
456 else if (conn->next) { /* && prev == 0 */
457 conn->next->prev = NULL;
458 this->firstusedconn = conn->next;
459 }
460 else if (conn->prev) { /* && next == 0 */
461 conn->prev->next = NULL;
462 this->lastusedconn = conn->prev;
463 }
464 else { /* if ((next == 0) && (prev == 0)) */
465 this->firstusedconn = NULL;
466 this->lastusedconn = NULL;
467 }
468
469 /* Initialise structures */
470 memset(conn, 0, sizeof(*conn));
471
472 /* Insert into link of free */
473 if (this->firstfreeconn) {
474 this->firstfreeconn->prev = conn;
475 }
476 else { /* First insert */
477 this->lastfreeconn = conn;
478 }
479
480 conn->next = this->firstfreeconn;
481 this->firstfreeconn = conn;
482
483 if (paranoid) dhcp_validate(this);
484
485 return 0;
486 }
487
488
489 /**
490 * dhcp_checkconn()
491 * Checks connections to see if the lease has expired
492 **/
dhcp_checkconn(struct dhcp_t * this)493 int dhcp_checkconn(struct dhcp_t *this)
494 {
495 struct dhcp_conn_t *conn;
496 time_t now = mainclock;
497
498 now -= this->lease;
499 conn = this->firstusedconn;
500 while (conn) {
501 if (now > conn->lasttime) {
502 if (this->debug)
503 log_dbg("DHCP timeout: Removing connection");
504 dhcp_freeconn(conn, RADIUS_TERMINATE_CAUSE_LOST_CARRIER);
505 return 0; /* Returning after first deletion */
506 }
507 conn = conn->next;
508 }
509 return 0;
510 }
511
512 /**
513 * dhcp_new()
514 * Allocates a new instance of the library
515 **/
516
517 int
dhcp_new(struct dhcp_t ** pdhcp,int numconn,char * interface,int usemac,uint8_t * mac,int promisc,struct in_addr * listen,int lease,int allowdyn,struct in_addr * uamlisten,uint16_t uamport,int useeapol)518 dhcp_new(struct dhcp_t **pdhcp, int numconn, char *interface,
519 int usemac, uint8_t *mac, int promisc,
520 struct in_addr *listen, int lease, int allowdyn,
521 struct in_addr *uamlisten, uint16_t uamport, int useeapol) {
522 struct dhcp_t *dhcp;
523
524 if (!(dhcp = *pdhcp = calloc(sizeof(struct dhcp_t), 1))) {
525 log_err(0, "calloc() failed");
526 return -1;
527 }
528
529 dhcp->numconn = numconn;
530
531 if (!(dhcp->conn = calloc(sizeof(struct dhcp_conn_t), numconn))) {
532 log_err(0, "calloc() failed");
533 free(dhcp);
534 return -1;
535 }
536
537 dhcp_initconn(dhcp);
538
539 if (net_init(&dhcp->ipif, interface, PKT_ETH_PROTO_IP, promisc, usemac ? mac : 0) < 0) {
540 free(dhcp->conn);
541 free(dhcp);
542 return -1;
543 }
544
545 #if defined (__FreeBSD__) || defined (__APPLE__) || defined (__OpenBSD__)
546 {
547 int blen=0;
548 if (ioctl(dhcp->ipif.fd, BIOCGBLEN, &blen) < 0) {
549 log_err(errno,"ioctl() failed!");
550 }
551 dhcp->rbuf_max = blen;
552 if (!(dhcp->rbuf = calloc(dhcp->rbuf_max, 1))) {
553 /* TODO: Free malloc */
554 log_err(errno, "malloc() failed");
555 }
556 dhcp->rbuf_offset = 0;
557 dhcp->rbuf_len = 0;
558 }
559 #endif
560
561 if (net_init(&dhcp->arpif, interface, PKT_ETH_PROTO_ARP, promisc, usemac ? mac : 0) < 0) {
562 close(dhcp->ipif.fd);
563 free(dhcp->conn);
564 free(dhcp);
565 return -1; /* Error reporting done in dhcp_open_eth */
566 }
567
568 if (useeapol) {
569 if (net_init(&dhcp->eapif, interface, PKT_ETH_PROTO_EAPOL, promisc, usemac ? mac : 0) < 0) {
570 close(dhcp->ipif.fd);
571 close(dhcp->arpif.fd);
572 free(dhcp->conn);
573 free(dhcp);
574 return -1; /* Error reporting done in eapol_open_eth */
575 }
576 }
577
578 if (options.dhcpgwip.s_addr != 0) {
579 int fd;
580 struct sockaddr_in addr;
581 int on = 1;
582
583 memset(&addr, 0, sizeof(addr));
584 addr.sin_family = AF_INET;
585 addr.sin_addr.s_addr = htonl(INADDR_ANY);
586 addr.sin_port = htons(68);
587
588 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ||
589 bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
590 log_err(errno, "socket or bind failed for dhcp relay!");
591 close(dhcp->ipif.fd);
592 close(dhcp->arpif.fd);
593 close(dhcp->eapif.fd);
594 free(dhcp->conn);
595 free(dhcp);
596 close(fd);
597 return -1;
598 }
599
600 if (setsockopt(dhcp->relayfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
601 log_err(errno, "Can't set reuse option");
602 }
603
604 dhcp->relayfd = fd;
605 }
606
607 if (dhcp_hashinit(dhcp, dhcp->numconn))
608 return -1; /* Failed to allocate hash tables */
609
610 /* Initialise various variables */
611 dhcp->ourip.s_addr = listen->s_addr;
612 dhcp->lease = lease;
613 dhcp->allowdyn = allowdyn;
614 dhcp->uamlisten.s_addr = uamlisten->s_addr;
615 dhcp->uamport = uamport;
616
617 /* Initialise call back functions */
618 dhcp->cb_data_ind = 0;
619 dhcp->cb_eap_ind = 0;
620 dhcp->cb_request = 0;
621 dhcp->cb_disconnect = 0;
622 dhcp->cb_connect = 0;
623
624 return 0;
625 }
626
627 /**
628 * dhcp_set()
629 * Set dhcp parameters which can be altered at runtime.
630 **/
631 int
dhcp_set(struct dhcp_t * dhcp,int debug)632 dhcp_set(struct dhcp_t *dhcp, int debug) {
633 dhcp->debug = debug;
634 dhcp->anydns = options.uamanydns;
635
636 /* Copy list of uamserver IP addresses */
637 if (dhcp->authip) free(dhcp->authip);
638 dhcp->authiplen = options.uamserverlen;
639
640 if (!(dhcp->authip = calloc(sizeof(struct in_addr), options.uamserverlen))) {
641 log_err(0, "calloc() failed");
642 dhcp->authip = 0;
643 return -1;
644 }
645
646 memcpy(dhcp->authip, &options.uamserver, sizeof(struct in_addr) * options.uamserverlen);
647
648 return 0;
649 }
650
651 /**
652 * dhcp_free()
653 * Releases ressources allocated to the instance of the library
654 **/
dhcp_free(struct dhcp_t * dhcp)655 int dhcp_free(struct dhcp_t *dhcp) {
656 if (dhcp->hash) free(dhcp->hash);
657 if (dhcp->authip) free(dhcp->authip);
658 dev_set_flags(dhcp->ipif.devname, dhcp->ipif.devflags);
659 net_close(&dhcp->ipif);
660 net_close(&dhcp->arpif);
661 net_close(&dhcp->eapif);
662 free(dhcp->conn);
663 free(dhcp);
664 return 0;
665 }
666
667 /**
668 * dhcp_timeout()
669 * Need to call this function at regular intervals to clean up old connections.
670 **/
671 int
dhcp_timeout(struct dhcp_t * this)672 dhcp_timeout(struct dhcp_t *this)
673 {
674 if (paranoid)
675 dhcp_validate(this);
676
677 dhcp_checkconn(this);
678
679 return 0;
680 }
681
682 /**
683 * dhcp_timeleft()
684 * Use this function to find out when to call dhcp_timeout()
685 * If service is needed after the value given by tvp then tvp
686 * is left unchanged.
687 **/
dhcp_timeleft(struct dhcp_t * this,struct timeval * tvp)688 struct timeval* dhcp_timeleft(struct dhcp_t *this, struct timeval *tvp) {
689 return tvp;
690 }
691
check_garden(pass_through * ptlist,int ptcnt,struct pkt_ippacket_t * pack,int dst)692 int check_garden(pass_through *ptlist, int ptcnt, struct pkt_ippacket_t *pack, int dst) {
693 struct pkt_tcphdr_t *tcph = (struct pkt_tcphdr_t *)pack->payload;
694 struct pkt_udphdr_t *udph = (struct pkt_udphdr_t *)pack->payload;
695 pass_through *pt;
696 int i;
697
698 for (i = 0; i < ptcnt; i++) {
699 pt = &ptlist[i];
700 if (pt->proto == 0 || pack->iph.protocol == pt->proto)
701 if (pt->host.s_addr == 0 ||
702 pt->host.s_addr == ((dst ? pack->iph.daddr : pack->iph.saddr) & pt->mask.s_addr))
703 if (pt->port == 0 ||
704 (pack->iph.protocol == PKT_IP_PROTO_TCP && (dst ? tcph->dst : tcph->src) == htons(pt->port)) ||
705 (pack->iph.protocol == PKT_IP_PROTO_UDP && (dst ? udph->dst : udph->src) == htons(pt->port)))
706 return 1;
707 }
708
709 return 0;
710 }
711
712 static
dhcp_nakDNS(struct dhcp_conn_t * conn,struct pkt_ippacket_t * pack,size_t len)713 int dhcp_nakDNS(struct dhcp_conn_t *conn, struct pkt_ippacket_t *pack, size_t len) {
714 struct dhcp_t *this = conn->parent;
715 struct pkt_udphdr_t *udph = (struct pkt_udphdr_t *)pack->payload;
716 /*struct dns_packet_t *dnsp = (struct dns_packet_t *)((char*)pack->payload + sizeof(struct pkt_udphdr_t));*/
717 struct dns_fullpacket_t answer;
718
719 memcpy(&answer, pack, len);
720
721 /* DNS response, with no host error code */
722 answer.dns.flags = htons(0x8583);
723
724 /* UDP */
725 answer.udph.src = udph->dst;
726 answer.udph.dst = udph->src;
727
728 /* IP */
729 answer.iph.check = 0; /* Calculate at end of packet */
730 memcpy(&answer.iph.daddr, &pack->iph.saddr, PKT_IP_ALEN);
731 memcpy(&answer.iph.saddr, &pack->iph.daddr, PKT_IP_ALEN);
732
733 /* Ethernet */
734 memcpy(&answer.ethh.dst, &pack->ethh.src, PKT_ETH_ALEN);
735 memcpy(&answer.ethh.src, &pack->ethh.dst, PKT_ETH_ALEN);
736 answer.ethh.prot = htons(PKT_ETH_PROTO_IP);
737
738 /* checksums */
739 chksum(&answer.iph);
740
741 dhcp_send(this, &this->ipif, conn->hismac, &answer, len);
742
743 return 0;
744 }
745
746 static
_filterDNSreq(struct dhcp_conn_t * conn,struct pkt_ippacket_t * pack,size_t plen)747 int _filterDNSreq(struct dhcp_conn_t *conn, struct pkt_ippacket_t *pack, size_t plen) {
748 /*struct dhcp_udphdr_t *udph = (struct dhcp_udphdr_t*)pack->payload;*/
749 struct dns_packet_t *dnsp = (struct dns_packet_t *)((char*)pack->payload + sizeof(struct pkt_udphdr_t));
750 size_t len = plen - DHCP_DNS_HLEN - PKT_UDP_HLEN - PKT_IP_HLEN - PKT_ETH_HLEN;
751 size_t olen = len;
752
753 uint16_t id = ntohs(dnsp->id);
754 uint16_t flags = ntohs(dnsp->flags);
755 uint16_t qdcount = ntohs(dnsp->qdcount);
756 uint16_t ancount = ntohs(dnsp->ancount);
757 uint16_t nscount = ntohs(dnsp->nscount);
758 uint16_t arcount = ntohs(dnsp->arcount);
759
760 uint8_t *p_pkt = (uint8_t *)dnsp->records;
761 char q[256];
762
763 int d = options.debug; /* XXX: debug */
764 int i;
765
766 if (d) log_dbg("DNS ID: %d", id);
767 if (d) log_dbg("DNS Flags: %d", flags);
768
769 /* it was a response? shouldn't be */
770 /*if (((flags & 0x8000) >> 15) == 1) return 0;*/
771
772 memset(q,0,sizeof(q));
773
774 #undef copyres
775 #define copyres(isq,n) \
776 if (d) log_dbg(#n ": %d", n ## count); \
777 for (i=0; i < n ## count; i++) \
778 if (dns_copy_res(isq, &p_pkt, &len, \
779 (uint8_t *)dnsp, olen, \
780 q, sizeof(q))) \
781 return dhcp_nakDNS(conn,pack,plen)
782
783 copyres(1,qd);
784 copyres(0,an);
785 copyres(0,ns);
786 copyres(0,ar);
787
788 if (d) log_dbg("left (should be zero): %d", len);
789
790 return 1;
791 }
792
793 static
_filterDNSresp(struct dhcp_conn_t * conn,struct pkt_ippacket_t * pack,size_t plen)794 int _filterDNSresp(struct dhcp_conn_t *conn, struct pkt_ippacket_t *pack, size_t plen) {
795 /*struct dhcp_udphdr_t *udph = (struct dhcp_udphdr_t*)pack->payload;*/
796 struct dns_packet_t *dnsp = (struct dns_packet_t *)((char*)pack->payload + sizeof(struct pkt_udphdr_t));
797 size_t len = plen - DHCP_DNS_HLEN - PKT_UDP_HLEN - PKT_IP_HLEN - PKT_ETH_HLEN;
798 size_t olen = len;
799
800 uint16_t id = ntohs(dnsp->id);
801 uint16_t flags = ntohs(dnsp->flags);
802 uint16_t qdcount = ntohs(dnsp->qdcount);
803 uint16_t ancount = ntohs(dnsp->ancount);
804 uint16_t nscount = ntohs(dnsp->nscount);
805 uint16_t arcount = ntohs(dnsp->arcount);
806
807 uint8_t *p_pkt = (uint8_t *)dnsp->records;
808 char q[256];
809
810 int d = options.debug; /* XXX: debug */
811 int i;
812
813 if (d) log_dbg("DNS ID: %d", id);
814 if (d) log_dbg("DNS Flags: %d", flags);
815
816 /* it was a query? shouldn't be */
817 if (((flags & 0x8000) >> 15) == 0) return 0;
818
819 memset(q,0,sizeof(q));
820
821 #undef copyres
822 #define copyres(isq,n) \
823 if (d) log_dbg(#n ": %d", n ## count); \
824 for (i=0; i < n ## count; i++) \
825 dns_copy_res(isq, &p_pkt, &len, \
826 (uint8_t *)dnsp, olen, \
827 q, sizeof(q))
828
829 copyres(1,qd);
830 copyres(0,an);
831 copyres(0,ns);
832 copyres(0,ar);
833
834 if (d) log_dbg("left (should be zero): %d", len);
835
836 /*
837 dnsp->flags = htons(flags);
838 dnsp->qdcount = htons(qdcount);
839 dnsp->ancount = htons(ancount);
840 dnsp->nscount = htons(nscount);
841 dnsp->arcount = htons(arcount);
842 */
843
844 return 1;
845 }
846
847
848 /**
849 * dhcp_doDNAT()
850 * Change destination address to authentication server.
851 **/
dhcp_doDNAT(struct dhcp_conn_t * conn,struct pkt_ippacket_t * pack,size_t len)852 int dhcp_doDNAT(struct dhcp_conn_t *conn,
853 struct pkt_ippacket_t *pack, size_t len) {
854 struct dhcp_t *this = conn->parent;
855 struct pkt_tcphdr_t *tcph = (struct pkt_tcphdr_t *)pack->payload;
856 struct pkt_udphdr_t *udph = (struct pkt_udphdr_t *)pack->payload;
857 int i;
858
859 /* Allow localhost through network... */
860 if (pack->iph.daddr == INADDR_LOOPBACK)
861 return 0;
862
863 /* Was it an ICMP request for us? */
864 if (pack->iph.protocol == PKT_IP_PROTO_ICMP)
865 if (pack->iph.daddr == conn->ourip.s_addr)
866 return 0;
867
868 /* Was it a DNS request? */
869 if (((this->anydns) ||
870 (pack->iph.daddr == conn->dns1.s_addr) ||
871 (pack->iph.daddr == conn->dns2.s_addr)) &&
872 (pack->iph.protocol == PKT_IP_PROTO_UDP && udph->dst == htons(DHCP_DNS))) {
873 if (options.dnsparanoia) {
874 if (_filterDNSreq(conn, pack, len))
875 return 0;
876 else /* drop */
877 return -1;
878 } else { /* allow */
879 return 0;
880 }
881 }
882
883 /* Was it a request for authentication server? */
884 for (i = 0; i<this->authiplen; i++) {
885 if ((pack->iph.daddr == this->authip[i].s_addr) /* &&
886 (pack->iph.protocol == PKT_IP_PROTO_TCP) &&
887 ((tcph->dst == htons(DHCP_HTTP)) ||
888 (tcph->dst == htons(DHCP_HTTPS)))*/)
889 return 0; /* Destination was authentication server */
890 }
891
892 /* Was it a request for local redirection server? */
893 if ((pack->iph.daddr == this->uamlisten.s_addr) &&
894 (pack->iph.protocol == PKT_IP_PROTO_TCP) &&
895 (tcph->dst == htons(this->uamport)))
896 return 0; /* Destination was local redir server */
897
898 /* Was it a request for a pass-through entry? */
899 if (check_garden(options.pass_throughs, options.num_pass_throughs, pack, 1))
900 return 0;
901 /* Check uamdomain driven walled garden */
902 if (check_garden(this->pass_throughs, this->num_pass_throughs, pack, 1))
903 return 0;
904
905 /* Check appconn session specific pass-throughs */
906 if (conn->peer) {
907 struct app_conn_t *appconn = (struct app_conn_t *)conn->peer;
908 if (check_garden(appconn->s_params.pass_throughs, appconn->s_params.pass_through_count, pack, 1))
909 return 0;
910 }
911
912 /* Was it a http request for another server? */
913 /* We are changing dest IP and dest port to local UAM server */
914 if ((pack->iph.protocol == PKT_IP_PROTO_TCP) &&
915 (tcph->dst == htons(DHCP_HTTP))) {
916 int n;
917 int pos=-1;
918
919 for (n=0; n<DHCP_DNAT_MAX; n++) {
920 if ((conn->dnatip[n] == pack->iph.daddr) &&
921 (conn->dnatport[n] == tcph->src)) {
922 pos = n;
923 break;
924 }
925 }
926 if (pos==-1) { /* Save for undoing */
927 if (options.usetap)
928 memcpy(conn->dnatmac[conn->nextdnat], pack->ethh.dst, PKT_ETH_ALEN);
929 conn->dnatip[conn->nextdnat] = pack->iph.daddr;
930 conn->dnatport[conn->nextdnat] = tcph->src;
931 conn->nextdnat = (conn->nextdnat + 1) % DHCP_DNAT_MAX;
932 }
933
934 if (options.usetap)
935 memcpy(pack->ethh.dst, tuntap(tun).hwaddr, PKT_ETH_ALEN);
936
937 pack->iph.daddr = this->uamlisten.s_addr;
938 tcph->dst = htons(this->uamport);
939
940 chksum(&pack->iph);
941 return 0;
942 }
943
944 return -1; /* Something else */
945
946 }
947
dhcp_postauthDNAT(struct dhcp_conn_t * conn,struct pkt_ippacket_t * pack,size_t len,int isreturn)948 int dhcp_postauthDNAT(struct dhcp_conn_t *conn, struct pkt_ippacket_t *pack, size_t len, int isreturn) {
949 struct dhcp_t *this = conn->parent;
950 struct pkt_tcphdr_t *tcph = (struct pkt_tcphdr_t *)pack->payload;
951 /*struct pkt_udphdr_t *udph = (struct pkt_udphdr_t *)pack->payload;*/
952
953 if (options.postauth_proxyport > 0) {
954 if (isreturn) {
955 if ((pack->iph.protocol == PKT_IP_PROTO_TCP) &&
956 (pack->iph.saddr == options.postauth_proxyip.s_addr) &&
957 (tcph->src == htons(options.postauth_proxyport))) {
958 int n;
959 for (n=0; n<DHCP_DNAT_MAX; n++) {
960 if (tcph->dst == conn->dnatport[n]) {
961 if (options.usetap)
962 memcpy(pack->ethh.src, conn->dnatmac[n], PKT_ETH_ALEN);
963 pack->iph.saddr = conn->dnatip[n];
964 tcph->src = htons(DHCP_HTTP);
965
966 chksum(&pack->iph);
967
968 return 0; /* It was a DNAT reply */
969 }
970 }
971 return 0;
972 }
973 }
974 else {
975 if ((pack->iph.protocol == PKT_IP_PROTO_TCP) &&
976 (tcph->dst == htons(DHCP_HTTP))) {
977
978 int n;
979 int pos=-1;
980
981 for (n = 0; n<this->authiplen; n++)
982 if ((pack->iph.daddr == this->authip[n].s_addr))
983 return 0;
984
985 for (n=0; n<DHCP_DNAT_MAX; n++) {
986 if ((conn->dnatip[n] == pack->iph.daddr) &&
987 (conn->dnatport[n] == tcph->src)) {
988 pos = n;
989 break;
990 }
991 }
992
993 if (pos==-1) { /* Save for undoing */
994 if (options.usetap)
995 memcpy(conn->dnatmac[conn->nextdnat], pack->ethh.dst, PKT_ETH_ALEN);
996 conn->dnatip[conn->nextdnat] = pack->iph.daddr;
997 conn->dnatport[conn->nextdnat] = tcph->src;
998 conn->nextdnat = (conn->nextdnat + 1) % DHCP_DNAT_MAX;
999 }
1000
1001 log_dbg("rewriting packet for post-auth proxy %s:%d",
1002 inet_ntoa(options.postauth_proxyip),
1003 options.postauth_proxyport);
1004
1005 pack->iph.daddr = options.postauth_proxyip.s_addr;
1006 tcph->dst = htons(options.postauth_proxyport);
1007
1008 chksum(&pack->iph);
1009
1010 return 0;
1011 }
1012 }
1013 }
1014
1015 return -1; /* Something else */
1016 }
1017
1018 /**
1019 * dhcp_undoDNAT()
1020 * Change source address back to original server
1021 **/
dhcp_undoDNAT(struct dhcp_conn_t * conn,struct pkt_ippacket_t * pack,size_t * plen)1022 int dhcp_undoDNAT(struct dhcp_conn_t *conn, struct pkt_ippacket_t *pack, size_t *plen) {
1023 struct dhcp_t *this = conn->parent;
1024 struct pkt_tcphdr_t *tcph = (struct pkt_tcphdr_t *)pack->payload;
1025 struct pkt_udphdr_t *udph = (struct pkt_udphdr_t *)pack->payload;
1026 /*size_t len = *plen;*/
1027 int i;
1028
1029 /* Allow localhost through network... */
1030 if (pack->iph.saddr == INADDR_LOOPBACK)
1031 return 0;
1032
1033 /* Was it a DNS reply? */
1034 if (((this->anydns) ||
1035 (pack->iph.saddr == conn->dns1.s_addr) ||
1036 (pack->iph.saddr == conn->dns2.s_addr)) &&
1037 (pack->iph.protocol == PKT_IP_PROTO_UDP && udph->src == htons(DHCP_DNS))) {
1038 if (options.uamdomains) {
1039 if (_filterDNSresp(conn, pack, *plen))
1040 return 0;
1041 else
1042 return -1; /* drop */
1043 } else { /* always let through dns when not filtering */
1044 return 0;
1045 }
1046 }
1047
1048 if (pack->iph.protocol == PKT_IP_PROTO_ICMP) {
1049 /* Was it an ICMP reply from us? */
1050 if (pack->iph.saddr == conn->ourip.s_addr)
1051 return 0;
1052 /* Allow for MTU negotiation */
1053 if (options.debug)
1054 log_dbg("Received ICMP type=%d code=%d",
1055 (int)pack->payload[0],(int)pack->payload[1]);
1056 switch((unsigned char)pack->payload[0]) {
1057 case 0: /* echo reply */
1058 case 3: /* destination unreachable */
1059 case 5: /* redirect */
1060 case 11: /* time excedded */
1061 switch((unsigned char)pack->payload[1]) {
1062 case 4:
1063 log(LOG_NOTICE, "Fragmentation needed ICMP");
1064 }
1065 if (options.debug)
1066 log_dbg("Forwarding ICMP to chilli client");
1067 return 0;
1068 }
1069 /* fail all else */
1070 return -1;
1071 }
1072
1073 /*
1074 12:46:20.767600 IP 10.1.0.1.49335 > 68.142.197.198.80: S 1442428713:1442428713(0) win 65535 <mss 1460,sackOK,eol>
1075 12:46:20.768234 IP 10.1.0.10.3990 > 10.1.0.1.49335: S 746818639:746818639(0) ack 1442428714 win 5840 <mss 1460,nop,nop,sackOK>
1076 */
1077
1078 /* Was it a reply from redir server? */
1079 if ((pack->iph.saddr == this->uamlisten.s_addr) &&
1080 (pack->iph.protocol == PKT_IP_PROTO_TCP) &&
1081 (tcph->src == htons(this->uamport))) {
1082 int n;
1083
1084 for (n=0; n<DHCP_DNAT_MAX; n++) {
1085 if (tcph->dst == conn->dnatport[n]) {
1086
1087 if (options.usetap)
1088 memcpy(pack->ethh.src, conn->dnatmac[n], PKT_ETH_ALEN);
1089
1090 pack->iph.saddr = conn->dnatip[n];
1091 tcph->src = htons(DHCP_HTTP);
1092
1093 chksum(&pack->iph);
1094
1095 return 0; /* It was a DNAT reply */
1096 }
1097 }
1098 return 0; /* It was a normal reply from redir server */
1099 }
1100
1101 /* Was it a normal http or https reply from authentication server? */
1102 /* Was it a normal reply from authentication server? */
1103 for (i = 0; i<this->authiplen; i++) {
1104 if ((pack->iph.saddr == this->authip[i].s_addr) /* &&
1105 (pack->iph.protocol == PKT_IP_PROTO_TCP) &&
1106 ((tcph->src == htons(DHCP_HTTP)) ||
1107 (tcph->src == htons(DHCP_HTTPS)))*/)
1108 return 0; /* Destination was authentication server */
1109 }
1110
1111 /* Was it a reply for a pass-through entry? */
1112 if (check_garden(options.pass_throughs, options.num_pass_throughs, pack, 0))
1113 return 0;
1114 if (check_garden(this->pass_throughs, this->num_pass_throughs, pack, 0))
1115 return 0;
1116
1117 /* Check appconn session specific pass-throughs */
1118 if (conn->peer) {
1119 struct app_conn_t *appconn = (struct app_conn_t *)conn->peer;
1120 if (check_garden(appconn->s_params.pass_throughs, appconn->s_params.pass_through_count, pack, 0))
1121 return 0;
1122 }
1123
1124 return -1; /* Something else */
1125 }
1126
1127 /**
1128 * dhcp_checkDNS()
1129 * Check if it was request for known domain name.
1130 * In case it was a request for a known keyword then
1131 * redirect to the login/logout page
1132 * 2005-09-19: This stuff is highly experimental.
1133 **/
dhcp_checkDNS(struct dhcp_conn_t * conn,struct pkt_ippacket_t * pack,size_t len)1134 int dhcp_checkDNS(struct dhcp_conn_t *conn,
1135 struct pkt_ippacket_t *pack, size_t len) {
1136
1137 struct dhcp_t *this = conn->parent;
1138 struct pkt_udphdr_t *udph = (struct pkt_udphdr_t *)pack->payload;
1139 struct dns_packet_t *dnsp = (struct dns_packet_t *)((char*)pack->payload + sizeof(struct pkt_udphdr_t));
1140 struct dns_fullpacket_t answer;
1141 uint8_t *p1 = NULL;
1142 uint8_t *p2 = NULL;
1143 size_t length;
1144 size_t udp_len;
1145 uint8_t query[256];
1146 size_t query_len = 0;
1147 int n;
1148
1149 log_dbg("DNS ID: %d", ntohs(dnsp->id));
1150 log_dbg("DNS flags: %d", ntohs(dnsp->flags));
1151
1152 if ((ntohs(dnsp->flags) == 0x0100) &&
1153 (ntohs(dnsp->qdcount) == 0x0001) &&
1154 (ntohs(dnsp->ancount) == 0x0000) &&
1155 (ntohs(dnsp->nscount) == 0x0000) &&
1156 (ntohs(dnsp->arcount) == 0x0000)) {
1157
1158 log_dbg("It was a query %s", dnsp->records);
1159
1160 p1 = dnsp->records + 1 + dnsp->records[0];
1161 p2 = dnsp->records;
1162
1163 do {
1164 if (query_len < 256)
1165 query[query_len++] = *p2;
1166 } while (*p2++ != 0); /* TODO */
1167
1168 for (n=0; n<4; n++) {
1169 if (query_len < 256)
1170 query[query_len++] = *p2++;
1171 }
1172
1173 query[query_len++] = 0xc0;
1174 query[query_len++] = 0x0c;
1175 query[query_len++] = 0x00;
1176 query[query_len++] = 0x01;
1177 query[query_len++] = 0x00;
1178 query[query_len++] = 0x01;
1179 query[query_len++] = 0x00;
1180 query[query_len++] = 0x00;
1181 query[query_len++] = 0x01;
1182 query[query_len++] = 0x2c;
1183 query[query_len++] = 0x00;
1184 query[query_len++] = 0x04;
1185 memcpy(&query[query_len], &conn->ourip.s_addr, 4);
1186 query_len += 4;
1187
1188 if (!memcmp(p1,
1189 "\3key\12chillispot\3org",
1190 sizeof("\3key\12chillispot\3org"))) {
1191 log_dbg("It was a matching query %s: \n", dnsp->records);
1192 memcpy(&answer, pack, len); /* TODO */
1193
1194 /* DNS Header */
1195 answer.dns.id = dnsp->id;
1196 answer.dns.flags = htons(0x8000);
1197 answer.dns.qdcount = htons(0x0001);
1198 answer.dns.ancount = htons(0x0001);
1199 answer.dns.nscount = htons(0x0000);
1200 answer.dns.arcount = htons(0x0000);
1201 memcpy(answer.dns.records, query, query_len);
1202
1203 /* UDP header */
1204 udp_len = query_len + DHCP_DNS_HLEN + PKT_UDP_HLEN;
1205 answer.udph.len = htons(udp_len);
1206 answer.udph.src = udph->dst;
1207 answer.udph.dst = udph->src;
1208
1209 /* IP header */
1210 answer.iph.version_ihl = PKT_IP_VER_HLEN;
1211 answer.iph.tos = 0;
1212 answer.iph.tot_len = htons(udp_len + PKT_IP_HLEN);
1213 answer.iph.id = 0;
1214 answer.iph.frag_off = 0;
1215 answer.iph.ttl = 0x10;
1216 answer.iph.protocol = 0x11;
1217 answer.iph.check = 0; /* Calculate at end of packet */
1218 memcpy(&answer.iph.daddr, &pack->iph.saddr, PKT_IP_ALEN);
1219 memcpy(&answer.iph.saddr, &pack->iph.saddr, PKT_IP_ALEN);
1220
1221 /* Ethernet header */
1222 memcpy(&answer.ethh.dst, &pack->ethh.src, PKT_ETH_ALEN);
1223 memcpy(&answer.ethh.src, &pack->ethh.dst, PKT_ETH_ALEN);
1224 answer.ethh.prot = htons(PKT_ETH_PROTO_IP);
1225
1226 /* Work out checksums */
1227 chksum(&answer.iph);
1228
1229 /* Calculate total length */
1230 length = udp_len + PKT_IP_HLEN + PKT_ETH_HLEN;
1231
1232 return dhcp_send(this, &this->ipif, conn->hismac, &answer, length);
1233 }
1234 }
1235 return -1; /* Something else */
1236 }
1237
1238 /**
1239 * dhcp_getdefault()
1240 * Fill in a DHCP packet with most essential values
1241 **/
1242 int
dhcp_getdefault(struct dhcp_fullpacket_t * pack)1243 dhcp_getdefault(struct dhcp_fullpacket_t *pack) {
1244
1245 /* Initialise reply packet with request */
1246 memset(pack, 0, sizeof(struct dhcp_fullpacket_t));
1247
1248 /* DHCP Payload */
1249 pack->dhcp.op = DHCP_BOOTREPLY;
1250 pack->dhcp.htype = DHCP_HTYPE_ETH;
1251 pack->dhcp.hlen = PKT_ETH_ALEN;
1252
1253 /* IP header */
1254 pack->iph.version_ihl = PKT_IP_VER_HLEN;
1255 pack->iph.tos = 0;
1256 pack->iph.tot_len = 0; /* Calculate at end of packet */
1257 pack->iph.id = 0;
1258 pack->iph.frag_off = 0;
1259 pack->iph.ttl = 0x10;
1260 pack->iph.protocol = 0x11;
1261 pack->iph.check = 0; /* Calculate at end of packet */
1262
1263 /* Ethernet header */
1264 pack->ethh.prot = htons(PKT_ETH_PROTO_IP);
1265
1266 return 0;
1267 }
1268
1269 /**
1270 * dhcp_create_pkt()
1271 * Create a new typed DHCP packet
1272 */
1273 int
dhcp_create_pkt(uint8_t type,struct dhcp_fullpacket_t * pack,struct dhcp_fullpacket_t * req,struct dhcp_conn_t * conn)1274 dhcp_create_pkt(uint8_t type, struct dhcp_fullpacket_t *pack,
1275 struct dhcp_fullpacket_t *req, struct dhcp_conn_t *conn) {
1276 struct dhcp_t *this = conn->parent;
1277 int pos = 0;
1278
1279 dhcp_getdefault(pack);
1280
1281 pack->dhcp.xid = req->dhcp.xid;
1282 pack->dhcp.flags[0] = req->dhcp.flags[0];
1283 pack->dhcp.flags[1] = req->dhcp.flags[1];
1284 pack->dhcp.giaddr = req->dhcp.giaddr;
1285
1286 memcpy(&pack->dhcp.chaddr, &req->dhcp.chaddr, DHCP_CHADDR_LEN);
1287 memcpy(&pack->dhcp.sname, conn->dhcp_opts.sname, DHCP_SNAME_LEN);
1288 memcpy(&pack->dhcp.file, conn->dhcp_opts.file, DHCP_FILE_LEN);
1289
1290 log_dbg("!!! dhcp server : %s !!!", pack->dhcp.sname);
1291
1292 switch(type) {
1293 case DHCPOFFER:
1294 pack->dhcp.yiaddr = conn->hisip.s_addr;
1295 break;
1296 case DHCPACK:
1297 pack->dhcp.xid = req->dhcp.xid;
1298 pack->dhcp.ciaddr = req->dhcp.ciaddr;
1299 pack->dhcp.yiaddr = conn->hisip.s_addr;
1300 break;
1301 case DHCPNAK:
1302 break;
1303 }
1304
1305 /* Ethernet Header */
1306 memcpy(pack->ethh.dst, conn->hismac, PKT_ETH_ALEN);
1307 memcpy(pack->ethh.src, this->ipif.hwaddr, PKT_ETH_ALEN);
1308
1309 /* UDP and IP Headers */
1310 pack->udph.src = htons(DHCP_BOOTPS);
1311 pack->iph.saddr = conn->ourip.s_addr;
1312
1313 /** http://www.faqs.org/rfcs/rfc1542.html
1314 BOOTREQUEST fields BOOTREPLY values for UDP, IP, link-layer
1315 +-----------------------+-----------------------------------------+
1316 | 'ciaddr' 'giaddr' B | UDP dest IP destination link dest |
1317 +-----------------------+-----------------------------------------+
1318 | non-zero X X | BOOTPC (68) 'ciaddr' normal |
1319 | 0.0.0.0 non-zero X | BOOTPS (67) 'giaddr' normal |
1320 | 0.0.0.0 0.0.0.0 0 | BOOTPC (68) 'yiaddr' 'chaddr' |
1321 | 0.0.0.0 0.0.0.0 1 | BOOTPC (68) 255.255.255.255 broadcast |
1322 +-----------------------+-----------------------------------------+
1323
1324 B = BROADCAST flag
1325
1326 X = Don't care
1327
1328 normal = determine from the given IP destination using normal
1329 IP routing mechanisms and/or ARP as for any other
1330 normal datagram
1331
1332 If the 'giaddr' field in a DHCP message from a client is non-zero,
1333 the server sends any return messages to the 'DHCP server' port on the
1334 BOOTP relay agent whose address appears in 'giaddr'.
1335
1336 If the 'giaddr' field is zero and the 'ciaddr' field is nonzero, then the
1337 server unicasts DHCPOFFER and DHCPACK messages to the address in
1338 'ciaddr'.
1339
1340 If 'giaddr' is zero and 'ciaddr' is zero, and the broadcast bit is set,
1341 then the server broadcasts DHCPOFFER and DHCPACK messages to
1342 0xffffffff.
1343
1344 If the broadcast bit is not set and 'giaddr' is zero and 'ciaddr' is
1345 zero, then the server unicasts DHCPOFFER and DHCPACK messages to the
1346 client's hardware address and 'yiaddr' address.
1347
1348 In all cases, when 'giaddr' is zero, the server broadcasts any DHCPNAK
1349 messages to 0xffffffff.
1350
1351 **/
1352
1353 if (req->dhcp.ciaddr) {
1354 pack->iph.daddr = req->dhcp.ciaddr;
1355 pack->udph.dst = htons(DHCP_BOOTPC);
1356 } else if (req->dhcp.giaddr) {
1357 pack->iph.daddr = req->dhcp.giaddr;
1358 pack->udph.dst = htons(DHCP_BOOTPS);
1359 } else if (type == DHCPNAK || req->dhcp.flags[0] & 0x80) {
1360 pack->iph.daddr = ~0;
1361 pack->udph.dst = htons(DHCP_BOOTPC);
1362 pack->dhcp.flags[0] = 0x80;
1363 } else {
1364 pack->iph.daddr = pack->dhcp.yiaddr;
1365 pack->udph.dst = htons(DHCP_BOOTPC);
1366 }
1367
1368 /* Magic cookie */
1369 pack->dhcp.options[pos++] = 0x63;
1370 pack->dhcp.options[pos++] = 0x82;
1371 pack->dhcp.options[pos++] = 0x53;
1372 pack->dhcp.options[pos++] = 0x63;
1373
1374 pack->dhcp.options[pos++] = DHCP_OPTION_MESSAGE_TYPE;
1375 pack->dhcp.options[pos++] = 1;
1376 pack->dhcp.options[pos++] = type;
1377
1378 memcpy(&pack->dhcp.options[pos], conn->dhcp_opts.options, DHCP_OPTIONS_LEN-pos);
1379 pos += conn->dhcp_opts.option_length;
1380
1381 return pos;
1382 }
1383
1384
1385 /**
1386 * dhcp_gettag()
1387 * Search a DHCP packet for a particular tag.
1388 * Returns -1 if not found.
1389 **/
dhcp_gettag(struct dhcp_packet_t * pack,size_t length,struct dhcp_tag_t ** tag,uint8_t tagtype)1390 int dhcp_gettag(struct dhcp_packet_t *pack, size_t length,
1391 struct dhcp_tag_t **tag, uint8_t tagtype) {
1392 struct dhcp_tag_t *t;
1393 size_t offset = DHCP_MIN_LEN + DHCP_OPTION_MAGIC_LEN;
1394
1395 /* if (length > DHCP_LEN) {
1396 log_warn(0,"Length of dhcp packet larger then %d: %d", DHCP_LEN, length);
1397 length = DHCP_LEN;
1398 } */
1399
1400 while ((offset + 2) < length) {
1401 t = (struct dhcp_tag_t *)(((void *)pack) + offset);
1402 if (t->t == tagtype) {
1403 if ((offset + 2 + (size_t)(t->l)) > length)
1404 return -1; /* Tag length too long */
1405 *tag = t;
1406 return 0;
1407 }
1408 offset += 2 + t->l;
1409 }
1410
1411 return -1; /* Not found */
1412 }
1413
1414
1415 /**
1416 * dhcp_sendOFFER()
1417 * Send of a DHCP offer message to a peer.
1418 **/
dhcp_sendOFFER(struct dhcp_conn_t * conn,struct dhcp_fullpacket_t * pack,size_t len)1419 int dhcp_sendOFFER(struct dhcp_conn_t *conn,
1420 struct dhcp_fullpacket_t *pack, size_t len) {
1421
1422 struct dhcp_t *this = conn->parent;
1423 struct dhcp_fullpacket_t packet;
1424 uint16_t length = 576 + 4; /* Maximum length */
1425 uint16_t udp_len = 576 - 20; /* Maximum length */
1426 size_t pos = 0;
1427
1428 /* Get packet default values */
1429 pos = dhcp_create_pkt(DHCPOFFER, &packet, pack, conn);
1430
1431 /* DHCP Payload */
1432
1433 packet.dhcp.options[pos++] = DHCP_OPTION_SUBNET_MASK;
1434 packet.dhcp.options[pos++] = 4;
1435 memcpy(&packet.dhcp.options[pos], &conn->hismask.s_addr, 4);
1436 pos += 4;
1437
1438 packet.dhcp.options[pos++] = DHCP_OPTION_ROUTER_OPTION;
1439 packet.dhcp.options[pos++] = 4;
1440 memcpy(&packet.dhcp.options[pos], &conn->ourip.s_addr, 4);
1441 pos += 4;
1442
1443 /* Insert DNS Servers if given */
1444 if (conn->dns1.s_addr && conn->dns2.s_addr) {
1445 packet.dhcp.options[pos++] = DHCP_OPTION_DNS;
1446 packet.dhcp.options[pos++] = 8;
1447 memcpy(&packet.dhcp.options[pos], &conn->dns1.s_addr, 4);
1448 pos += 4;
1449 memcpy(&packet.dhcp.options[pos], &conn->dns2.s_addr, 4);
1450 pos += 4;
1451 }
1452 else if (conn->dns1.s_addr) {
1453 packet.dhcp.options[pos++] = DHCP_OPTION_DNS;
1454 packet.dhcp.options[pos++] = 4;
1455 memcpy(&packet.dhcp.options[pos], &conn->dns1.s_addr, 4);
1456 pos += 4;
1457 }
1458 else if (conn->dns2.s_addr) {
1459 packet.dhcp.options[pos++] = DHCP_OPTION_DNS;
1460 packet.dhcp.options[pos++] = 4;
1461 memcpy(&packet.dhcp.options[pos], &conn->dns2.s_addr, 4);
1462 pos += 4;
1463 }
1464
1465 /* Insert Domain Name if present */
1466 if (strlen(conn->domain)) {
1467 packet.dhcp.options[pos++] = DHCP_OPTION_DOMAIN_NAME;
1468 packet.dhcp.options[pos++] = strlen(conn->domain);
1469 memcpy(&packet.dhcp.options[pos], &conn->domain, strlen(conn->domain));
1470 pos += strlen(conn->domain);
1471 }
1472
1473 packet.dhcp.options[pos++] = DHCP_OPTION_LEASE_TIME;
1474 packet.dhcp.options[pos++] = 4;
1475 packet.dhcp.options[pos++] = (this->lease >> 24) & 0xFF;
1476 packet.dhcp.options[pos++] = (this->lease >> 16) & 0xFF;
1477 packet.dhcp.options[pos++] = (this->lease >> 8) & 0xFF;
1478 packet.dhcp.options[pos++] = (this->lease >> 0) & 0xFF;
1479
1480 /* Must be listening address */
1481 packet.dhcp.options[pos++] = DHCP_OPTION_SERVER_ID;
1482 packet.dhcp.options[pos++] = 4;
1483 memcpy(&packet.dhcp.options[pos], &conn->ourip.s_addr, 4);
1484 pos += 4;
1485
1486 packet.dhcp.options[pos++] = DHCP_OPTION_END;
1487
1488 /* UDP header */
1489 udp_len = pos + DHCP_MIN_LEN + PKT_UDP_HLEN;
1490 packet.udph.len = htons(udp_len);
1491
1492 /* IP header */
1493 packet.iph.tot_len = htons(udp_len + PKT_IP_HLEN);
1494
1495 /* Work out checksums */
1496 chksum(&packet.iph);
1497
1498 /* Calculate total length */
1499 length = udp_len + PKT_IP_HLEN + PKT_ETH_HLEN;
1500
1501 return dhcp_send(this, &this->ipif, conn->hismac, &packet, length);
1502 }
1503
1504 /**
1505 * dhcp_sendACK()
1506 * Send of a DHCP acknowledge message to a peer.
1507 **/
dhcp_sendACK(struct dhcp_conn_t * conn,struct dhcp_fullpacket_t * pack,size_t len)1508 int dhcp_sendACK(struct dhcp_conn_t *conn,
1509 struct dhcp_fullpacket_t *pack, size_t len) {
1510
1511 struct dhcp_t *this = conn->parent;
1512 struct dhcp_fullpacket_t packet;
1513 uint16_t length = 576 + 4; /* Maximum length */
1514 uint16_t udp_len = 576 - 20; /* Maximum length */
1515 size_t pos = 0;
1516
1517 /* Get packet default values */
1518 pos = dhcp_create_pkt(DHCPACK, &packet, pack, conn);
1519
1520 /* DHCP Payload */
1521 packet.dhcp.options[pos++] = DHCP_OPTION_SUBNET_MASK;
1522 packet.dhcp.options[pos++] = 4;
1523 memcpy(&packet.dhcp.options[pos], &conn->hismask.s_addr, 4);
1524 pos += 4;
1525
1526 packet.dhcp.options[pos++] = DHCP_OPTION_ROUTER_OPTION;
1527 packet.dhcp.options[pos++] = 4;
1528 memcpy(&packet.dhcp.options[pos], &conn->ourip.s_addr, 4);
1529 pos += 4;
1530
1531 /* Insert DNS Servers if given */
1532 if (conn->dns1.s_addr && conn->dns2.s_addr) {
1533 packet.dhcp.options[pos++] = DHCP_OPTION_DNS;
1534 packet.dhcp.options[pos++] = 8;
1535 memcpy(&packet.dhcp.options[pos], &conn->dns1.s_addr, 4);
1536 pos += 4;
1537 memcpy(&packet.dhcp.options[pos], &conn->dns2.s_addr, 4);
1538 pos += 4;
1539 }
1540 else if (conn->dns1.s_addr) {
1541 packet.dhcp.options[pos++] = DHCP_OPTION_DNS;
1542 packet.dhcp.options[pos++] = 4;
1543 memcpy(&packet.dhcp.options[pos], &conn->dns1.s_addr, 4);
1544 pos += 4;
1545 }
1546 else if (conn->dns2.s_addr) {
1547 packet.dhcp.options[pos++] = DHCP_OPTION_DNS;
1548 packet.dhcp.options[pos++] = 4;
1549 memcpy(&packet.dhcp.options[pos], &conn->dns2.s_addr, 4);
1550 pos += 4;
1551 }
1552
1553 /* Insert Domain Name if present */
1554 if (strlen(conn->domain)) {
1555 packet.dhcp.options[pos++] = DHCP_OPTION_DOMAIN_NAME;
1556 packet.dhcp.options[pos++] = strlen(conn->domain);
1557 memcpy(&packet.dhcp.options[pos], &conn->domain, strlen(conn->domain));
1558 pos += strlen(conn->domain);
1559 }
1560
1561 packet.dhcp.options[pos++] = DHCP_OPTION_LEASE_TIME;
1562 packet.dhcp.options[pos++] = 4;
1563 packet.dhcp.options[pos++] = (this->lease >> 24) & 0xFF;
1564 packet.dhcp.options[pos++] = (this->lease >> 16) & 0xFF;
1565 packet.dhcp.options[pos++] = (this->lease >> 8) & 0xFF;
1566 packet.dhcp.options[pos++] = (this->lease >> 0) & 0xFF;
1567
1568 /*
1569 packet.dhcp.options[pos++] = DHCP_OPTION_INTERFACE_MTU;
1570 packet.dhcp.options[pos++] = 2;
1571 packet.dhcp.options[pos++] = (conn->mtu >> 8) & 0xFF;
1572 packet.dhcp.options[pos++] = (conn->mtu >> 0) & 0xFF;
1573 */
1574
1575 /* Must be listening address */
1576 packet.dhcp.options[pos++] = DHCP_OPTION_SERVER_ID;
1577 packet.dhcp.options[pos++] = 4;
1578 memcpy(&packet.dhcp.options[pos], &conn->ourip.s_addr, 4);
1579 pos += 4;
1580
1581 packet.dhcp.options[pos++] = DHCP_OPTION_END;
1582
1583 /* UDP header */
1584 udp_len = pos + DHCP_MIN_LEN + PKT_UDP_HLEN;
1585 packet.udph.len = htons(udp_len);
1586
1587 /* IP header */
1588 packet.iph.tot_len = htons(udp_len + PKT_IP_HLEN);
1589
1590 /* Work out checksums */
1591 chksum(&packet.iph);
1592
1593 /* Calculate total length */
1594 length = udp_len + PKT_IP_HLEN + PKT_ETH_HLEN;
1595
1596 return dhcp_send(this, &this->ipif, conn->hismac, &packet, length);
1597 }
1598
1599 /**
1600 * dhcp_sendNAK()
1601 * Send of a DHCP negative acknowledge message to a peer.
1602 * NAK messages are always sent to broadcast IP address (
1603 * except when using a DHCP relay server)
1604 **/
dhcp_sendNAK(struct dhcp_conn_t * conn,struct dhcp_fullpacket_t * pack,size_t len)1605 int dhcp_sendNAK(struct dhcp_conn_t *conn,
1606 struct dhcp_fullpacket_t *pack, size_t len) {
1607
1608 struct dhcp_t *this = conn->parent;
1609 struct dhcp_fullpacket_t packet;
1610 uint16_t length = 576 + 4; /* Maximum length */
1611 uint16_t udp_len = 576 - 20; /* Maximum length */
1612 size_t pos = 0;
1613
1614 /* Get packet default values */
1615 pos = dhcp_create_pkt(DHCPNAK, &packet, pack, conn);
1616
1617 /* DHCP Payload */
1618
1619 /* Must be listening address */
1620 packet.dhcp.options[pos++] = DHCP_OPTION_SERVER_ID;
1621 packet.dhcp.options[pos++] = 4;
1622 memcpy(&packet.dhcp.options[pos], &conn->ourip.s_addr, 4);
1623 pos += 4;
1624
1625 packet.dhcp.options[pos++] = DHCP_OPTION_END;
1626
1627 /* UDP header */
1628 udp_len = pos + DHCP_MIN_LEN + PKT_UDP_HLEN;
1629 packet.udph.len = htons(udp_len);
1630
1631 /* IP header */
1632 packet.iph.tot_len = htons(udp_len + PKT_IP_HLEN);
1633
1634 /* Work out checksums */
1635 chksum(&packet.iph);
1636
1637 /* Calculate total length */
1638 length = udp_len + PKT_IP_HLEN + PKT_ETH_HLEN;
1639
1640 return dhcp_send(this, &this->ipif, conn->hismac, &packet, length);
1641 }
1642
1643
1644 /**
1645 * dhcp_getreq()
1646 * Process a received DHCP request and sends a response.
1647 **/
dhcp_getreq(struct dhcp_t * this,struct dhcp_fullpacket_t * pack,size_t len)1648 int dhcp_getreq(struct dhcp_t *this, struct dhcp_fullpacket_t *pack, size_t len) {
1649 uint8_t mac[PKT_ETH_ALEN];
1650 struct dhcp_tag_t *message_type = 0;
1651 struct dhcp_tag_t *requested_ip = 0;
1652 struct dhcp_conn_t *conn;
1653 struct in_addr addr;
1654
1655 if (pack->udph.dst != htons(DHCP_BOOTPS))
1656 return 0; /* Not a DHCP packet */
1657
1658 if (dhcp_gettag(&pack->dhcp, ntohs(pack->udph.len)-PKT_UDP_HLEN,
1659 &message_type, DHCP_OPTION_MESSAGE_TYPE)) {
1660 return -1;
1661 }
1662
1663 if (message_type->l != 1)
1664 return -1; /* Wrong length of message type */
1665
1666 if (pack->dhcp.giaddr)
1667 memcpy(mac, pack->dhcp.chaddr, PKT_ETH_ALEN);
1668 else
1669 memcpy(mac, pack->ethh.src, PKT_ETH_ALEN);
1670
1671 switch(message_type->v[0]) {
1672
1673 case DHCPRELEASE:
1674 dhcp_release_mac(this, mac, RADIUS_TERMINATE_CAUSE_LOST_CARRIER);
1675
1676 case DHCPDISCOVER:
1677 case DHCPREQUEST:
1678 case DHCPINFORM:
1679 break;
1680
1681 default:
1682 return 0; /* Unsupported message type */
1683 }
1684
1685 if (this->relayfd > 0) {
1686 /** Relay the DHCP request **/
1687 struct sockaddr_in addr;
1688
1689 memset(&addr, 0, sizeof(addr));
1690 addr.sin_family = AF_INET;
1691 addr.sin_addr.s_addr = options.dhcpgwip.s_addr;
1692 addr.sin_port = htons(options.dhcpgwport);
1693
1694 if (options.dhcprelayip.s_addr)
1695 pack->dhcp.giaddr = options.dhcprelayip.s_addr;
1696 else
1697 pack->dhcp.giaddr = options.uamlisten.s_addr;
1698
1699 /* if we can't send, lets do dhcp ourselves */
1700 if (sendto(this->relayfd, &pack->dhcp, ntohs(pack->udph.len) - PKT_UDP_HLEN, 0,
1701 (struct sockaddr *)&addr, sizeof(addr)) < 0) {
1702 log_err(errno, "could not relay DHCP request!");
1703 }
1704 else {
1705 return 0;
1706 }
1707 }
1708
1709 if (message_type->v[0] == DHCPRELEASE) {
1710 /* No Reply to client is sent */
1711 return 0;
1712 }
1713
1714 /* Check to see if we know MAC address. If not allocate new conn */
1715 if (dhcp_hashget(this, &conn, mac)) {
1716
1717 /* Do we allow dynamic allocation of IP addresses? */
1718 if (!this->allowdyn) /* TODO: Should be deleted! */
1719 return 0;
1720
1721 /* Allocate new connection */
1722 if (dhcp_newconn(this, &conn, mac)) /* TODO: Delete! */
1723 return 0; /* Out of connections */
1724 }
1725
1726 /* Request an IP address */
1727 if (conn->authstate == DHCP_AUTH_NONE) {
1728 addr.s_addr = pack->dhcp.ciaddr;
1729 if (this->cb_request)
1730 if (this->cb_request(conn, &addr, pack, len)) {
1731 return 0; /* Ignore request if IP address was not allocated */
1732 }
1733 }
1734
1735 conn->lasttime = mainclock;
1736
1737 /* Discover message */
1738 /* If an IP address was assigned offer it to the client */
1739 /* Otherwise ignore the request */
1740 if (message_type->v[0] == DHCPDISCOVER) {
1741 if (conn->hisip.s_addr)
1742 dhcp_sendOFFER(conn, pack, len);
1743 return 0;
1744 }
1745
1746 /* Request message */
1747 if (message_type->v[0] == DHCPREQUEST) {
1748
1749 if (!conn->hisip.s_addr) {
1750 if (this->debug) log_dbg("hisip not set");
1751 return dhcp_sendNAK(conn, pack, len);
1752 }
1753
1754 if (!memcmp(&conn->hisip.s_addr, &pack->dhcp.ciaddr, 4)) {
1755 if (this->debug) log_dbg("hisip match ciaddr");
1756 return dhcp_sendACK(conn, pack, len);
1757 }
1758
1759 if (!dhcp_gettag(&pack->dhcp, ntohs(pack->udph.len)-PKT_UDP_HLEN,
1760 &requested_ip, DHCP_OPTION_REQUESTED_IP)) {
1761 if (!memcmp(&conn->hisip.s_addr, requested_ip->v, 4))
1762 return dhcp_sendACK(conn, pack, len);
1763 }
1764
1765 if (this->debug) log_dbg("Sending NAK to client");
1766 return dhcp_sendNAK(conn, pack, len);
1767 }
1768
1769 /*
1770 * Unsupported DHCP message: Ignore
1771 */
1772 if (this->debug) log_dbg("Unsupported DHCP message ignored");
1773 return 0;
1774 }
1775
1776
1777 /**
1778 * dhcp_set_addrs()
1779 * Set various IP addresses of a connection.
1780 **/
dhcp_set_addrs(struct dhcp_conn_t * conn,struct in_addr * hisip,struct in_addr * hismask,struct in_addr * ourip,struct in_addr * ourmask,struct in_addr * dns1,struct in_addr * dns2,char * domain)1781 int dhcp_set_addrs(struct dhcp_conn_t *conn, struct in_addr *hisip,
1782 struct in_addr *hismask, struct in_addr *ourip,
1783 struct in_addr *ourmask, struct in_addr *dns1,
1784 struct in_addr *dns2, char *domain) {
1785
1786 conn->hisip.s_addr = hisip->s_addr;
1787 conn->hismask.s_addr = hismask->s_addr;
1788 conn->ourip.s_addr = ourip->s_addr;
1789 conn->dns1.s_addr = dns1->s_addr;
1790 conn->dns2.s_addr = dns2->s_addr;
1791
1792 if (domain) {
1793 strncpy(conn->domain, domain, DHCP_DOMAIN_LEN);
1794 conn->domain[DHCP_DOMAIN_LEN-1] = 0;
1795 }
1796 else {
1797 conn->domain[0] = 0;
1798 }
1799
1800 if (options.uamanyip &&
1801 (hisip->s_addr & ourmask->s_addr) != (ourip->s_addr & ourmask->s_addr)) {
1802 /**
1803 * We have enabled ''uamanyip'' and the address we are setting does
1804 * not fit in ourip's network. In this case, add a route entry.
1805 */
1806 struct app_conn_t *appconn = (struct app_conn_t *)conn->peer;
1807 if (appconn) {
1808 struct ippoolm_t *ipm = (struct ippoolm_t*)appconn->uplink;
1809 if (ipm && ipm->inuse == 2) {
1810 struct in_addr mask;
1811 mask.s_addr = 0xffffffff;
1812 log_dbg("Adding route for %s %d", inet_ntoa(*hisip),
1813 net_add_route(hisip, ourip, &mask));
1814 }
1815 }
1816 }
1817
1818 return 0;
1819 }
1820
1821 static unsigned char const bmac[PKT_ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
1822
dhcp_receive_ip(struct dhcp_t * this,struct pkt_ippacket_t * pack,size_t len)1823 int dhcp_receive_ip(struct dhcp_t *this, struct pkt_ippacket_t *pack, size_t len) {
1824 struct pkt_tcphdr_t *tcph = (struct pkt_tcphdr_t*) pack->payload;
1825 /*struct pkt_udphdr_t *udph = (struct pkt_udphdr_t*) pack->payload;*/
1826 struct dhcp_conn_t *conn;
1827 struct in_addr ourip;
1828 struct in_addr addr;
1829
1830 /*
1831 * Received a packet from the dhcpif
1832 */
1833
1834 if (this->debug)
1835 log_dbg("DHCP packet received");
1836
1837 /*
1838 * Check that the destination MAC address is our MAC or Broadcast
1839 */
1840 if ((memcmp(pack->ethh.dst, this->ipif.hwaddr, PKT_ETH_ALEN)) &&
1841 (memcmp(pack->ethh.dst, bmac, PKT_ETH_ALEN))) {
1842 log_dbg("dropping packet; not for our MAC or broadcast");
1843 return 0;
1844 }
1845
1846 ourip.s_addr = this->ourip.s_addr;
1847
1848 /*
1849 * DHCP (BOOTPS) packets for broadcast or us specifically
1850 */
1851 if (((pack->iph.daddr == 0) ||
1852 (pack->iph.daddr == 0xffffffff) ||
1853 (pack->iph.daddr == ourip.s_addr)) &&
1854 ((pack->iph.version_ihl == PKT_IP_VER_HLEN) &&
1855 (pack->iph.protocol == PKT_IP_PROTO_UDP) &&
1856 (((struct dhcp_fullpacket_t*)pack)->udph.dst == htons(DHCP_BOOTPS)))) {
1857 log_dbg("dhcp/bootps request being processed");
1858 return dhcp_getreq(this, (struct dhcp_fullpacket_t*) pack, len);
1859 }
1860
1861 /*
1862 * Check to see if we know MAC address
1863 */
1864 if (!dhcp_hashget(this, &conn, pack->ethh.src)) {
1865 if (this->debug) log_dbg("Address found");
1866 ourip.s_addr = conn->ourip.s_addr;
1867 }
1868 else {
1869 /* ALPAPAD */
1870 struct in_addr reqaddr;
1871 /* Get local copy */
1872 memcpy(&reqaddr.s_addr, &pack->iph.saddr, PKT_IP_ALEN);
1873
1874 if (options.debug)
1875 log_dbg("Address not found (%s)", inet_ntoa(reqaddr));
1876
1877 /* Do we allow dynamic allocation of IP addresses? */
1878 if (!this->allowdyn && !options.uamanyip)
1879 return 0;
1880
1881 /* Allocate new connection */
1882 if (dhcp_newconn(this, &conn, pack->ethh.src)) {
1883 if (this->debug)
1884 log_dbg("dropping packet; out of connections");
1885 return 0; /* Out of connections */
1886 }
1887 }
1888
1889 /* Request an IP address
1890 if (options.uamanyip &&
1891 conn->authstate == DHCP_AUTH_NONE) {
1892 this->cb_request(conn, &pack->iph.saddr);
1893 } */
1894
1895 /* Return if we do not know peer */
1896 if (!conn) {
1897 if (this->debug)
1898 log_dbg("dropping packet; no peer");
1899 return 0;
1900 }
1901
1902 /*
1903 * Request an IP address
1904 */
1905 if ((conn->authstate == DHCP_AUTH_NONE) &&
1906 (options.uamanyip ||
1907 ((pack->iph.daddr != 0) &&
1908 (pack->iph.daddr != 0xffffffff)))) {
1909 addr.s_addr = pack->iph.saddr;
1910 if (this->cb_request)
1911 if (this->cb_request(conn, &addr, 0, 0)) {
1912 if (this->debug)
1913 log_dbg("dropping packet; ip not known");
1914 return 0; /* Ignore request if IP address was not allocated */
1915 }
1916 }
1917
1918
1919 conn->lasttime = mainclock;
1920
1921 /*
1922 if (((pack->iph.daddr == conn->dns1.s_addr) ||
1923 (pack->iph.daddr == conn->dns2.s_addr)) &&
1924 (pack->iph.protocol == PKT_IP_PROTO_UDP) &&
1925 (udph->dst == htons(DHCP_DNS))) {
1926 if (dhcp_checkDNS(conn, pack, len)) return 0;
1927 }*/
1928
1929 /* Was it a request for the auto-logout service? */
1930 if ((pack->iph.daddr == options.uamlogout.s_addr) &&
1931 (pack->iph.protocol == PKT_IP_PROTO_TCP) &&
1932 (tcph->dst == htons(DHCP_HTTP))) {
1933 if (conn->peer) {
1934 struct app_conn_t *appconn = (struct app_conn_t *)conn->peer;
1935 if (appconn->s_state.authenticated) {
1936 terminate_appconn(appconn, RADIUS_TERMINATE_CAUSE_USER_REQUEST);
1937 if (options.debug)
1938 log_dbg("Dropping session due to request for auto-logout ip");
1939 appconn->uamexit=1;
1940 }
1941 }
1942 }
1943
1944 switch (conn->authstate) {
1945 case DHCP_AUTH_PASS:
1946 /* Check for post-auth proxy, otherwise pass packets unmodified */
1947 dhcp_postauthDNAT(conn, pack, len, 0);
1948 break;
1949
1950 case DHCP_AUTH_UNAUTH_TOS:
1951 /* Set TOS to specified value (unauthenticated) */
1952 pack->iph.tos = conn->unauth_cp;
1953 chksum(&pack->iph);
1954 break;
1955
1956 case DHCP_AUTH_AUTH_TOS:
1957 /* Set TOS to specified value (authenticated) */
1958 pack->iph.tos = conn->auth_cp;
1959 chksum(&pack->iph);
1960 break;
1961
1962 case DHCP_AUTH_SPLASH:
1963 dhcp_doDNAT(conn, pack, len);
1964 break;
1965
1966 case DHCP_AUTH_DNAT:
1967 /* Destination NAT if request to unknown web server */
1968 if (dhcp_doDNAT(conn, pack, len)) {
1969 if (this->debug) log_dbg("dropping packet; not nat'ed");
1970 return 0; /* Drop is not http or dns */
1971 }
1972 break;
1973
1974 case DHCP_AUTH_DROP:
1975 default:
1976 if (this->debug)
1977 log_dbg("dropping packet; auth-drop");
1978 return 0;
1979 }
1980
1981 /*done:*/
1982
1983 if (options.usetap) {
1984 struct pkt_ethhdr_t *ethh = (struct pkt_ethhdr_t *)pack;
1985 memcpy(ethh->dst,tuntap(tun).hwaddr,PKT_ETH_ALEN);
1986 }
1987
1988 if ((conn->hisip.s_addr) && (this->cb_data_ind)) {
1989 this->cb_data_ind(conn, pack, len);
1990 } else {
1991 if (this->debug)
1992 log_dbg("no hisip; packet-drop");
1993 }
1994
1995 return 0;
1996 }
1997
1998 /**
1999 * Call this function when a new IP packet has arrived. This function
2000 * should be part of a select() loop in the application.
2001 **/
dhcp_decaps(struct dhcp_t * this)2002 int dhcp_decaps(struct dhcp_t *this) {
2003 struct pkt_ippacket_t packet;
2004 ssize_t length;
2005
2006 if ((length = net_read(&this->ipif, &packet, sizeof(packet))) < 0)
2007 return -1;
2008
2009 if (this->debug) {
2010 struct pkt_ethhdr_t *ethh = &packet.ethh;
2011 log_dbg("dhcp_decaps: dst=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x src=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x prot=%.4x",
2012 ethh->dst[0],ethh->dst[1],ethh->dst[2],ethh->dst[3],ethh->dst[4],ethh->dst[5],
2013 ethh->src[0],ethh->src[1],ethh->src[2],ethh->src[3],ethh->src[4],ethh->src[5],
2014 ntohs(ethh->prot));
2015 }
2016
2017 return dhcp_receive_ip(this, &packet, length);
2018 }
2019
dhcp_relay_decaps(struct dhcp_t * this)2020 int dhcp_relay_decaps(struct dhcp_t *this) {
2021 struct dhcp_tag_t *message_type = 0;
2022 struct dhcp_fullpacket_t fullpack;
2023 struct dhcp_conn_t *conn;
2024 struct dhcp_packet_t packet;
2025 struct sockaddr_in addr;
2026 socklen_t fromlen = sizeof(addr);
2027 ssize_t length;
2028
2029
2030 if ((length = recvfrom(this->relayfd, &packet, sizeof(packet), 0,
2031 (struct sockaddr *) &addr, &fromlen)) <= 0) {
2032 log_err(errno, "recvfrom() failed");
2033 return -1;
2034 }
2035
2036 log_dbg("DHCP relay response of length %d received", length);
2037
2038 if (addr.sin_addr.s_addr != options.dhcpgwip.s_addr) {
2039 log_err(0, "received DHCP response from host other than our gateway");
2040 return -1;
2041 }
2042
2043 if (addr.sin_port != htons(options.dhcpgwport)) {
2044 log_err(0, "received DHCP response from port other than our gateway");
2045 return -1;
2046 }
2047
2048 if (dhcp_gettag(&packet, length, &message_type, DHCP_OPTION_MESSAGE_TYPE)) {
2049 log_err(0, "no message type");
2050 return -1;
2051 }
2052
2053 if (message_type->l != 1) {
2054 log_err(0, "wrong message type length");
2055 return -1; /* Wrong length of message type */
2056 }
2057
2058 if (dhcp_hashget(this, &conn, packet.chaddr)) {
2059
2060 /* Allocate new connection */
2061 if (dhcp_newconn(this, &conn, packet.chaddr)) {
2062 log_err(0, "out of connections");
2063 return 0; /* Out of connections */
2064 }
2065
2066 this->cb_request(conn, (struct in_addr *)&packet.yiaddr, 0, 0);
2067 }
2068
2069 packet.giaddr = 0;
2070
2071 memset(&fullpack, 0, sizeof(fullpack));
2072
2073 memcpy(fullpack.ethh.dst, conn->hismac, PKT_ETH_ALEN);
2074 memcpy(fullpack.ethh.src, this->ipif.hwaddr, PKT_ETH_ALEN);
2075 fullpack.ethh.prot = htons(PKT_ETH_PROTO_IP);
2076
2077 fullpack.iph.version_ihl = PKT_IP_VER_HLEN;
2078 fullpack.iph.tot_len = htons(length + PKT_UDP_HLEN + PKT_IP_HLEN);
2079 fullpack.iph.ttl = 0x10;
2080 fullpack.iph.protocol = 0x11;
2081
2082 fullpack.iph.saddr = conn->ourip.s_addr;
2083 fullpack.udph.src = htons(DHCP_BOOTPS);
2084 fullpack.udph.len = htons(length + PKT_UDP_HLEN);
2085
2086 /*if (fullpack.dhcp.ciaddr) {
2087 fullpack.udph.daddr = req->dhcp.ciaddr;
2088 fullpack.udph.dst = htons(DHCP_BOOTPC);
2089 } else if (req->dhcp.giaddr) {
2090 fullpack.iph.daddr = req->dhcp.giaddr;
2091 fullpack.udph.dst = htons(DHCP_BOOTPS);
2092 } else */
2093
2094 if (message_type->v[0] == DHCPNAK || packet.flags[0] & 0x80) {
2095 fullpack.iph.daddr = ~0;
2096 fullpack.udph.dst = htons(DHCP_BOOTPC);
2097 fullpack.dhcp.flags[0] = 0x80;
2098 } if (packet.ciaddr) {
2099 fullpack.iph.daddr = packet.ciaddr;
2100 fullpack.udph.dst = htons(DHCP_BOOTPC);
2101 } else {
2102 fullpack.iph.daddr = packet.yiaddr;
2103 fullpack.udph.dst = htons(DHCP_BOOTPC);
2104 }
2105
2106 memcpy(&fullpack.dhcp, &packet, sizeof(packet));
2107
2108 { /* rewrite the server-id, otherwise will not get subsequent requests */
2109 struct dhcp_tag_t *tag = 0;
2110 if (!dhcp_gettag(&fullpack.dhcp, length, &tag, DHCP_OPTION_SERVER_ID)) {
2111 memcpy(tag->v, &conn->ourip.s_addr, 4);
2112 }
2113 }
2114
2115 chksum(&fullpack.iph);
2116
2117 return dhcp_send(this, &this->ipif, conn->hismac, &fullpack,
2118 length + PKT_UDP_HLEN + PKT_IP_HLEN + PKT_ETH_HLEN);
2119 }
2120
2121 /**
2122 * dhcp_data_req()
2123 * Call this function to send an IP packet to the peer.
2124 * Called from the tun_ind function. This method is passed either
2125 * an Ethernet frame or an IP packet.
2126 **/
dhcp_data_req(struct dhcp_conn_t * conn,void * pack,size_t len,int ethhdr)2127 int dhcp_data_req(struct dhcp_conn_t *conn, void *pack, size_t len, int ethhdr) {
2128 struct dhcp_t *this = conn->parent;
2129 struct pkt_ippacket_t packet;
2130 size_t length = len;
2131
2132 if (ethhdr) { /* Ethernet frame */
2133 memcpy(&packet, pack, len);
2134 } else { /* IP packet */
2135 memcpy(&packet.iph, pack, len);
2136 length += PKT_ETH_HLEN;
2137 }
2138
2139 /* Ethernet header */
2140 memcpy(packet.ethh.dst, conn->hismac, PKT_ETH_ALEN);
2141 memcpy(packet.ethh.src, this->ipif.hwaddr, PKT_ETH_ALEN);
2142 packet.ethh.prot = htons(PKT_ETH_PROTO_IP);
2143
2144 switch (conn->authstate) {
2145
2146 case DHCP_AUTH_PASS:
2147 case DHCP_AUTH_AUTH_TOS:
2148 dhcp_postauthDNAT(conn, &packet, length, 1);
2149 break;
2150
2151 case DHCP_AUTH_SPLASH:
2152 case DHCP_AUTH_UNAUTH_TOS:
2153 dhcp_undoDNAT(conn, &packet, &length);
2154 break;
2155
2156 case DHCP_AUTH_DNAT:
2157 /* undo destination NAT */
2158 if (dhcp_undoDNAT(conn, &packet, &length)) {
2159 if (this->debug) log_dbg("dhcp_undoDNAT() returns true");
2160 return 0;
2161 }
2162 break;
2163
2164 case DHCP_AUTH_DROP:
2165 default: return 0;
2166 }
2167
2168 return dhcp_send(this, &this->ipif, conn->hismac, &packet, length);
2169 }
2170
2171
2172 /**
2173 * dhcp_sendARP()
2174 * Send ARP message to peer
2175 **/
2176 static int
dhcp_sendARP(struct dhcp_conn_t * conn,struct arp_fullpacket_t * pack,size_t len)2177 dhcp_sendARP(struct dhcp_conn_t *conn, struct arp_fullpacket_t *pack, size_t len) {
2178
2179 struct dhcp_t *this = conn->parent;
2180 struct arp_fullpacket_t packet;
2181 struct in_addr reqaddr;
2182 size_t length = sizeof(packet);
2183
2184 /* Get local copy */
2185 memcpy(&reqaddr.s_addr, pack->arp.tpa, PKT_IP_ALEN);
2186
2187 /* Check that request is within limits */
2188
2189 /* Get packet default values */
2190 memset(&packet, 0, sizeof(packet));
2191
2192 /* ARP Payload */
2193 packet.arp.hrd = htons(DHCP_HTYPE_ETH);
2194 packet.arp.pro = htons(PKT_ETH_PROTO_IP);
2195 packet.arp.hln = PKT_ETH_ALEN;
2196 packet.arp.pln = PKT_IP_ALEN;
2197 packet.arp.op = htons(DHCP_ARP_REPLY);
2198
2199 /* Source address */
2200 memcpy(packet.arp.sha, this->arpif.hwaddr, PKT_ETH_ALEN);
2201 memcpy(packet.arp.spa, &reqaddr.s_addr, PKT_IP_ALEN);
2202
2203 /* Target address */
2204 memcpy(packet.arp.tha, &conn->hismac, PKT_ETH_ALEN);
2205 memcpy(packet.arp.tpa, &conn->hisip.s_addr, PKT_IP_ALEN);
2206
2207 /* Ethernet header */
2208 memcpy(packet.ethh.dst, conn->hismac, PKT_ETH_ALEN);
2209 memcpy(packet.ethh.src, this->ipif.hwaddr, PKT_ETH_ALEN);
2210 packet.ethh.prot = htons(PKT_ETH_PROTO_ARP);
2211
2212 return dhcp_send(this, &this->arpif, conn->hismac, &packet, length);
2213 }
2214
2215
dhcp_receive_arp(struct dhcp_t * this,struct arp_fullpacket_t * pack,size_t len)2216 int dhcp_receive_arp(struct dhcp_t *this,
2217 struct arp_fullpacket_t *pack, size_t len) {
2218
2219 unsigned char const bmac[PKT_ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
2220 struct dhcp_conn_t *conn;
2221 struct in_addr reqaddr;
2222 struct in_addr taraddr;
2223
2224 /* Check that this is ARP request */
2225 if (pack->arp.op != htons(DHCP_ARP_REQUEST)) {
2226 if (this->debug)
2227 log_dbg("Received other ARP than request!");
2228 return 0;
2229 }
2230
2231 /* Check that MAC address is our MAC or Broadcast */
2232 if ((memcmp(pack->ethh.dst, this->ipif.hwaddr, PKT_ETH_ALEN)) &&
2233 (memcmp(pack->ethh.dst, bmac, PKT_ETH_ALEN))) {
2234 if (this->debug)
2235 log_dbg("Received ARP request for other destination!");
2236 return 0;
2237 }
2238
2239 /* get sender IP address */
2240 memcpy(&reqaddr.s_addr, &pack->arp.spa, PKT_IP_ALEN);
2241
2242 /* get target IP address */
2243 memcpy(&taraddr.s_addr, &pack->arp.tpa, PKT_IP_ALEN);
2244
2245
2246 /* Check to see if we know MAC address. */
2247 if (dhcp_hashget(this, &conn, pack->ethh.src)) {
2248
2249 if (options.debug)
2250 log_dbg("Address not found: %s", inet_ntoa(reqaddr));
2251
2252 /* Do we allow dynamic allocation of IP addresses? */
2253 if (!this->allowdyn && !options.uamanyip) {
2254 if (this->debug)
2255 log_dbg("ARP: Unknown client and no dynip: %s", inet_ntoa(taraddr));
2256 return 0;
2257 }
2258
2259 /* Allocate new connection */
2260 if (dhcp_newconn(this, &conn, pack->ethh.src)) {
2261 log_warn(0, "ARP: out of connections");
2262 return 0; /* Out of connections */
2263 }
2264 }
2265
2266 /* if no sender ip, then client is checking their own ip */
2267 if (!reqaddr.s_addr) {
2268 /* XXX: lookup in ippool to see if we really do know who has this */
2269 /* XXX: it should also ack if *we* are that ip */
2270 if (this->debug)
2271 log_dbg("ARP: Ignoring self-discovery: %s", inet_ntoa(taraddr));
2272
2273 /* If a static ip address... */
2274 this->cb_request(conn, &taraddr, 0, 0);
2275
2276 return 0;
2277 }
2278
2279 if (!memcmp(&reqaddr.s_addr, &taraddr.s_addr, 4)) {
2280
2281 /* Request an IP address */
2282 if (options.uamanyip /*or static ip*/ &&
2283 conn->authstate == DHCP_AUTH_NONE) {
2284 this->cb_request(conn, &reqaddr, 0, 0);
2285 }
2286
2287 if (this->debug)
2288 log_dbg("ARP: gratuitous arp %s!", inet_ntoa(taraddr));
2289
2290 return 0;
2291 }
2292
2293 if (!conn->hisip.s_addr && !options.uamanyip) {
2294 if (this->debug)
2295 log_dbg("ARP: request did not come from known client!");
2296 return 0; /* Only reply if he was allocated an address */
2297 }
2298
2299 /* Is ARP request for clients own address: Ignore */
2300 if (conn->hisip.s_addr == taraddr.s_addr) {
2301 if (this->debug)
2302 log_dbg("ARP: hisip equals target ip: %s!",
2303 inet_ntoa(conn->hisip));
2304 return 0;
2305 }
2306
2307 if (!options.uamanyip) {
2308 /* If ARP request outside of mask: Ignore */
2309 if (reqaddr.s_addr &&
2310 (conn->hisip.s_addr & conn->hismask.s_addr) !=
2311 (reqaddr.s_addr & conn->hismask.s_addr)) {
2312 if (this->debug)
2313 log_dbg("ARP: request not in our subnet");
2314 return 0;
2315 }
2316
2317 if (memcmp(&conn->ourip.s_addr, &taraddr.s_addr, 4)) { /* if ourip differs from target ip */
2318 if (options.debug) {
2319 log_dbg("ARP: Did not ask for router address: %s", inet_ntoa(conn->ourip));
2320 log_dbg("ARP: Asked for target: %s", inet_ntoa(taraddr));
2321 }
2322 return 0; /* Only reply if he asked for his router address */
2323 }
2324 }
2325 else if ((taraddr.s_addr != options.dhcplisten.s_addr) &&
2326 ((taraddr.s_addr & options.mask.s_addr) == options.net.s_addr)) {
2327 /* when uamanyip is on we should ignore arp requests that ARE within our subnet except of course the ones for ourselves */
2328 if (options.debug)
2329 log_dbg("ARP: request for IP=%s other than us within our subnet(uamanyip on), ignoring", inet_ntoa(taraddr));
2330 return 0;
2331 }
2332
2333 conn->lasttime = mainclock;
2334
2335 dhcp_sendARP(conn, pack, len);
2336
2337 return 0;
2338 }
2339
2340
2341 /**
2342 * dhcp_arp_ind()
2343 * Call this function when a new ARP packet has arrived. This function
2344 * should be part of a select() loop in the application.
2345 **/
dhcp_arp_ind(struct dhcp_t * this)2346 int dhcp_arp_ind(struct dhcp_t *this) /* ARP Indication */
2347 {
2348 struct arp_fullpacket_t packet;
2349 ssize_t length;
2350
2351 if ((length = net_read(&this->arpif, &packet, sizeof(packet))) < 0)
2352 return -1;
2353
2354 if (options.debug) {
2355 struct pkt_ethhdr_t *ethh = &packet.ethh;
2356 log_dbg("arp_decaps: dst=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x src=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x prot=%.4x",
2357 ethh->dst[0],ethh->dst[1],ethh->dst[2],ethh->dst[3],ethh->dst[4],ethh->dst[5],
2358 ethh->src[0],ethh->src[1],ethh->src[2],ethh->src[3],ethh->src[4],ethh->src[5],
2359 ntohs(ethh->prot));
2360 }
2361
2362 dhcp_receive_arp(this, &packet, length);
2363
2364 return 0;
2365 }
2366
2367
2368 /**
2369 * eapol_sendNAK()
2370 * Send of a EAPOL negative acknowledge message to a peer.
2371 * NAK messages are always sent to broadcast IP address (
2372 * except when using a EAPOL relay server)
2373 **/
dhcp_senddot1x(struct dhcp_conn_t * conn,struct dot1xpacket_t * pack,size_t len)2374 int dhcp_senddot1x(struct dhcp_conn_t *conn,
2375 struct dot1xpacket_t *pack, size_t len) {
2376 struct dhcp_t *this = conn->parent;
2377 return dhcp_send(this, &this->eapif, conn->hismac, pack, len);
2378 }
2379
2380 /**
2381 * eapol_sendNAK()
2382 * Send of a EAPOL negative acknowledge message to a peer.
2383 * NAK messages are always sent to broadcast IP address (
2384 * except when using a EAPOL relay server)
2385 **/
dhcp_sendEAP(struct dhcp_conn_t * conn,void * pack,size_t len)2386 int dhcp_sendEAP(struct dhcp_conn_t *conn, void *pack, size_t len) {
2387
2388 struct dhcp_t *this = conn->parent;
2389 struct dot1xpacket_t packet;
2390
2391 /* Ethernet header */
2392 memcpy(packet.ethh.dst, conn->hismac, PKT_ETH_ALEN);
2393 memcpy(packet.ethh.src, this->ipif.hwaddr, PKT_ETH_ALEN);
2394 packet.ethh.prot = htons(PKT_ETH_PROTO_EAPOL);
2395
2396 /* 802.1x header */
2397 packet.dot1x.ver = 1;
2398 packet.dot1x.type = 0; /* EAP */
2399 packet.dot1x.len = htons((uint16_t)len);
2400
2401 memcpy(&packet.eap, pack, len);
2402
2403 return dhcp_send(this, &this->eapif, conn->hismac, &packet, (PKT_ETH_HLEN + 4 + len));
2404 }
2405
dhcp_sendEAPreject(struct dhcp_conn_t * conn,void * pack,size_t len)2406 int dhcp_sendEAPreject(struct dhcp_conn_t *conn, void *pack, size_t len) {
2407
2408 /*struct dhcp_t *this = conn->parent;*/
2409
2410 struct eap_packet_t packet;
2411
2412 if (pack) {
2413 dhcp_sendEAP(conn, pack, len);
2414 }
2415 else {
2416 memset(&packet, 0, sizeof(packet));
2417 packet.code = 4;
2418 packet.id = 1; /* TODO ??? */
2419 packet.length = htons(4);
2420
2421 dhcp_sendEAP(conn, &packet, 4);
2422 }
2423
2424 return 0;
2425
2426 }
2427
dhcp_receive_eapol(struct dhcp_t * this,struct dot1xpacket_t * pack)2428 int dhcp_receive_eapol(struct dhcp_t *this, struct dot1xpacket_t *pack) {
2429 struct dhcp_conn_t *conn = NULL;
2430 unsigned char const bmac[PKT_ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
2431 unsigned char const amac[PKT_ETH_ALEN] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x03};
2432
2433 /* Check to see if we know MAC address. */
2434 if (!dhcp_hashget(this, &conn, pack->ethh.src)) {
2435 if (this->debug) log_dbg("Address found");
2436 }
2437 else {
2438 if (this->debug) log_dbg("Address not found");
2439 }
2440
2441 if (this->debug)
2442 log_dbg("IEEE 802.1x Packet: %.2x, %.2x %d",
2443 pack->dot1x.ver, pack->dot1x.type,
2444 ntohs(pack->dot1x.len));
2445
2446 /* Check that MAC address is our MAC, Broadcast or authentication MAC */
2447 if ((memcmp(pack->ethh.dst, this->ipif.hwaddr, PKT_ETH_ALEN)) &&
2448 (memcmp(pack->ethh.dst, bmac, PKT_ETH_ALEN)) &&
2449 (memcmp(pack->ethh.dst, amac, PKT_ETH_ALEN)))
2450 return 0;
2451
2452 if (pack->dot1x.type == 1) { /* Start */
2453 struct dot1xpacket_t p;
2454 memset(&p, 0, sizeof(p));
2455
2456 /* Allocate new connection */
2457 if (conn == NULL) {
2458 if (dhcp_newconn(this, &conn, pack->ethh.src))
2459 return 0; /* Out of connections */
2460 }
2461
2462 /* Ethernet header */
2463 memcpy(p.ethh.dst, pack->ethh.src, PKT_ETH_ALEN);
2464 memcpy(p.ethh.src, this->ipif.hwaddr, PKT_ETH_ALEN);
2465 p.ethh.prot = htons(PKT_ETH_PROTO_EAPOL);
2466
2467 /* 802.1x header */
2468 p.dot1x.ver = 1;
2469 p.dot1x.type = 0; /* EAP */
2470 p.dot1x.len = htons(5);
2471
2472 /* EAP Packet */
2473 p.eap.code = 1;
2474 p.eap.id = 1;
2475 p.eap.length = htons(5);
2476 p.eap.type = 1; /* Identity */
2477
2478 dhcp_senddot1x(conn, &p, PKT_ETH_HLEN + 4 + 5);
2479 return 0;
2480 }
2481 else if (pack->dot1x.type == 0) { /* EAP */
2482
2483 /* TODO: Currently we only support authentications starting with a
2484 client sending a EAPOL start message. Need to also support
2485 authenticator initiated communications. */
2486 if (!conn)
2487 return 0;
2488
2489 conn->lasttime = mainclock;
2490
2491 if (this->cb_eap_ind)
2492 this->cb_eap_ind(conn, &pack->eap, ntohs(pack->eap.length));
2493
2494 return 0;
2495 }
2496 else { /* Check for logoff */
2497 return 0;
2498 }
2499 }
2500
2501 /**
2502 * dhcp_eapol_ind()
2503 * Call this function when a new EAPOL packet has arrived. This function
2504 * should be part of a select() loop in the application.
2505 **/
dhcp_eapol_ind(struct dhcp_t * this)2506 int dhcp_eapol_ind(struct dhcp_t *this) {
2507 struct dot1xpacket_t packet;
2508 ssize_t length;
2509
2510 if ((length = net_read(&this->eapif, &packet, sizeof(packet))) < 0)
2511 return -1;
2512
2513 if (options.debug) {
2514 struct pkt_ethhdr_t *ethh = &packet.ethh;
2515 log_dbg("eapol_decaps: dst=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x src=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x prot=%.4x",
2516 ethh->dst[0],ethh->dst[1],ethh->dst[2],ethh->dst[3],ethh->dst[4],ethh->dst[5],
2517 ethh->src[0],ethh->src[1],ethh->src[2],ethh->src[3],ethh->src[4],ethh->src[5],
2518 ntohs(ethh->prot));
2519 }
2520
2521 return dhcp_receive_eapol(this, &packet);
2522 }
2523
2524
2525 /**
2526 * dhcp_set_cb_eap_ind()
2527 * Set callback function which is called when packet has arrived
2528 * Used for eap packets
2529 **/
dhcp_set_cb_eap_ind(struct dhcp_t * this,int (* cb_eap_ind)(struct dhcp_conn_t * conn,void * pack,size_t len))2530 int dhcp_set_cb_eap_ind(struct dhcp_t *this,
2531 int (*cb_eap_ind) (struct dhcp_conn_t *conn, void *pack, size_t len)) {
2532 this->cb_eap_ind = cb_eap_ind;
2533 return 0;
2534 }
2535
2536
2537 /**
2538 * dhcp_set_cb_data_ind()
2539 * Set callback function which is called when packet has arrived
2540 **/
dhcp_set_cb_data_ind(struct dhcp_t * this,int (* cb_data_ind)(struct dhcp_conn_t * conn,void * pack,size_t len))2541 int dhcp_set_cb_data_ind(struct dhcp_t *this,
2542 int (*cb_data_ind) (struct dhcp_conn_t *conn, void *pack, size_t len)) {
2543 this->cb_data_ind = cb_data_ind;
2544 return 0;
2545 }
2546
2547
2548 /**
2549 * dhcp_set_cb_data_ind()
2550 * Set callback function which is called when a dhcp request is received
2551 **/
dhcp_set_cb_request(struct dhcp_t * this,int (* cb_request)(struct dhcp_conn_t * conn,struct in_addr * addr,struct dhcp_fullpacket_t * pack,size_t len))2552 int dhcp_set_cb_request(struct dhcp_t *this,
2553 int (*cb_request) (struct dhcp_conn_t *conn, struct in_addr *addr, struct dhcp_fullpacket_t *pack, size_t len)) {
2554 this->cb_request = cb_request;
2555 return 0;
2556 }
2557
2558
2559 /**
2560 * dhcp_set_cb_connect()
2561 * Set callback function which is called when a connection is created
2562 **/
dhcp_set_cb_connect(struct dhcp_t * this,int (* cb_connect)(struct dhcp_conn_t * conn))2563 int dhcp_set_cb_connect(struct dhcp_t *this,
2564 int (*cb_connect) (struct dhcp_conn_t *conn)) {
2565 this->cb_connect = cb_connect;
2566 return 0;
2567 }
2568
2569 /**
2570 * dhcp_set_cb_disconnect()
2571 * Set callback function which is called when a connection is deleted
2572 **/
dhcp_set_cb_disconnect(struct dhcp_t * this,int (* cb_disconnect)(struct dhcp_conn_t * conn,int term_cause))2573 int dhcp_set_cb_disconnect(struct dhcp_t *this,
2574 int (*cb_disconnect) (struct dhcp_conn_t *conn, int term_cause)) {
2575 this->cb_disconnect = cb_disconnect;
2576 return 0;
2577 }
2578
dhcp_set_cb_getinfo(struct dhcp_t * this,int (* cb_getinfo)(struct dhcp_conn_t * conn,bstring b,int fmt))2579 int dhcp_set_cb_getinfo(struct dhcp_t *this,
2580 int (*cb_getinfo) (struct dhcp_conn_t *conn, bstring b, int fmt)) {
2581 this->cb_getinfo = cb_getinfo;
2582 return 0;
2583 }
2584
2585
2586 #if defined (__FreeBSD__) || defined (__APPLE__) || defined (__OpenBSD__)
2587
dhcp_receive(struct dhcp_t * this)2588 int dhcp_receive(struct dhcp_t *this) {
2589 ssize_t length = 0;
2590 size_t offset = 0;
2591 struct bpf_hdr *hdrp;
2592 struct pkt_ethhdr_t *ethhdr;
2593
2594 if (this->rbuf_offset == this->rbuf_len) {
2595 length = net_read(&this->ipif, this->rbuf, this->rbuf_max);
2596
2597 if (length <= 0)
2598 return length;
2599
2600 this->rbuf_offset = 0;
2601 this->rbuf_len = length;
2602 }
2603
2604 while (this->rbuf_offset != this->rbuf_len) {
2605
2606 if (this->rbuf_len - this->rbuf_offset < sizeof(struct bpf_hdr)) {
2607 this->rbuf_offset = this->rbuf_len;
2608 continue;
2609 }
2610
2611 hdrp = (struct bpf_hdr *) &this->rbuf[this->rbuf_offset];
2612
2613 if (this->rbuf_offset + hdrp->bh_hdrlen + hdrp->bh_caplen >
2614 this->rbuf_len) {
2615 this->rbuf_offset = this->rbuf_len;
2616 continue;
2617 }
2618
2619 if (hdrp->bh_caplen != hdrp->bh_datalen) {
2620 this->rbuf_offset += hdrp->bh_hdrlen + hdrp->bh_caplen;
2621 continue;
2622 }
2623
2624 ethhdr = (struct pkt_ethhdr_t *)
2625 (this->rbuf + this->rbuf_offset + hdrp->bh_hdrlen);
2626
2627 switch (ntohs(ethhdr->prot)) {
2628 case PKT_ETH_PROTO_IP:
2629 dhcp_receive_ip(this, (struct pkt_ippacket_t*) ethhdr, hdrp->bh_caplen);
2630 break;
2631 case PKT_ETH_PROTO_ARP:
2632 dhcp_receive_arp(this, (struct arp_fullpacket_t*) ethhdr, hdrp->bh_caplen);
2633 break;
2634 case PKT_ETH_PROTO_EAPOL:
2635 dhcp_receive_eapol(this, (struct dot1xpacket_t*) ethhdr);
2636 break;
2637
2638 default:
2639 break;
2640 }
2641 this->rbuf_offset += hdrp->bh_hdrlen + hdrp->bh_caplen;
2642 };
2643 return (0);
2644 }
2645 #endif
2646