File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / coova-chilli / src / dhcp.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:48:25 2012 UTC (13 years, 1 month ago) by misho
Branches: coova-chilli, MAIN
CVS tags: v1_0_12, HEAD
coova-chilli

    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>