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>