Annotation of embedaddon/coova-chilli/src/dhcp.c, revision 1.1

1.1     ! misho       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>