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:
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:
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:
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:
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:
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: **/
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: **/
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: **/
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: **/
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: **/
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: **/
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: **/
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: **/
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: **/
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: **/
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
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_se()
629: * Set dhcp parameters which can be altered at runtime.
630: **/
631: int
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: **/
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
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: **/
688: struct timeval* dhcp_timeleft(struct dhcp_t *this, struct timeval *tvp) {
689: return tvp;
690: }
691:
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
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
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
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: **/
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:
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: **/
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: **/
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
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
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: **/
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: **/
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: **/
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: **/
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: **/
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: **/
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:
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: **/
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:
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: **/
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
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:
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: **/
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: **/
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: **/
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:
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:
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: **/
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: **/
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: **/
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: **/
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: **/
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: **/
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:
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:
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 = read(this->ipif.fd, 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
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>