VirtualBox

Changeset 22101 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Aug 8, 2009 6:22:29 AM (15 years ago)
Author:
vboxsync
Message:

NAT: dhcp rfc2131/rfc2132 step 1

Location:
trunk/src/VBox/Devices/Network/slirp
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Network/slirp/bootp.c

    r22027 r22101  
    2727
    2828static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
    29 
     29static void bootp_reply(PNATState pData, struct mbuf *m0, int off, uint16_t flags);
     30
     31static uint8_t *dhcp_find_option(uint8_t *vend, uint8_t tag)
     32{
     33    uint8_t *q = vend;
     34    uint8_t len;
     35    /*@todo magic validation */
     36    q += 4; /*magic*/
     37    while(*q != RFC1533_END)
     38    {
     39        if (*q == RFC1533_PAD)
     40            continue;
     41        if (*q == tag)
     42            return q;
     43        q++;
     44        len = *q;
     45        q += 1 + len;
     46    }
     47    return NULL;
     48}
     49static BOOTPClient *alloc_addr(PNATState pData)
     50{
     51    int i;
     52    for (i = 0; i < NB_ADDR; i++)
     53    {
     54        if (!bootp_clients[i].allocated)
     55        {
     56            BOOTPClient *bc;
     57
     58            bc = &bootp_clients[i];
     59            memset(bc, 0, sizeof(BOOTPClient));
     60            bc->allocated = 1;
     61            bc->number = i;
     62            return bc;
     63        }
     64    }
     65    return NULL;
     66}
    3067static BOOTPClient *get_new_addr(PNATState pData, struct in_addr *paddr)
    3168{
    32     int i;
    33 
     69    BOOTPClient *bc;
     70    bc = alloc_addr(pData);
     71    if (bc == NULL)
     72        return NULL;
     73    paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (bc->number + START_ADDR));
     74    bc->addr.s_addr = paddr->s_addr;
     75    return bc;
     76    return NULL;
     77}
     78
     79static int release_addr(PNATState pData, struct in_addr *paddr)
     80{
     81    unsigned i;
    3482    for (i = 0; i < NB_ADDR; i++)
    3583    {
    36         if (!bootp_clients[i].allocated)
    37         {
    38             BOOTPClient *bc;
    39 
    40             bc = &bootp_clients[i];
    41             bc->allocated = 1;
    42             paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR));
    43             bc->addr.s_addr = paddr->s_addr;
    44             return bc;
    45         }
    46     }
    47     return NULL;
    48 }
    49 
    50 static int release_addr(PNATState pData, struct in_addr *paddr)
    51 {
    52     unsigned i;
    53 
    54     i = ntohl(paddr->s_addr) - START_ADDR - ntohl(special_addr.s_addr);
    55     if (i >= NB_ADDR)
    56         return 0;
    57 
    58     memset(bootp_clients[i].macaddr, '\0', 6);
    59     bootp_clients[i].allocated = 0;
    60     return 1;
    61 }
    62 
     84        if (paddr->s_addr == bootp_clients[i].addr.s_addr)
     85        {
     86            memset(&bootp_clients[i], 0, sizeof(BOOTPClient));
     87            return 1;
     88        }
     89    }
     90    return 0;
     91}
     92
     93/*
     94 * from RFC 2131 4.3.1
     95 * Field      DHCPOFFER            DHCPACK             DHCPNAK
     96 * -----      ---------            -------             -------
     97 * 'op'       BOOTREPLY            BOOTREPLY           BOOTREPLY
     98 * 'htype'    (From "Assigned Numbers" RFC)
     99 * 'hlen'     (Hardware address length in octets)
     100 * 'hops'     0                    0                   0
     101 * 'xid'      'xid' from client    'xid' from client   'xid' from client
     102 *            DHCPDISCOVER         DHCPREQUEST         DHCPREQUEST
     103 *            message              message             message
     104 * 'secs'     0                    0                   0
     105 * 'ciaddr'   0                    'ciaddr' from       0
     106 *                                 DHCPREQUEST or 0
     107 * 'yiaddr'   IP address offered   IP address          0
     108 *            to client            assigned to client
     109 * 'siaddr'   IP address of next   IP address of next  0
     110 *            bootstrap server     bootstrap server
     111 * 'flags'    'flags' from         'flags' from        'flags' from
     112 *            client DHCPDISCOVER  client DHCPREQUEST  client DHCPREQUEST
     113 *            message              message             message
     114 * 'giaddr'   'giaddr' from        'giaddr' from       'giaddr' from
     115 *            client DHCPDISCOVER  client DHCPREQUEST  client DHCPREQUEST
     116 *            message              message             message
     117 * 'chaddr'   'chaddr' from        'chaddr' from       'chaddr' from
     118 *            client DHCPDISCOVER  client DHCPREQUEST  client DHCPREQUEST
     119 *            message              message             message
     120 * 'sname'    Server host name     Server host name    (unused)
     121 *            or options           or options
     122 * 'file'     Client boot file     Client boot file    (unused)
     123 *            name or options      name or options
     124 * 'options'  options              options
     125 *
     126 * Option                    DHCPOFFER    DHCPACK            DHCPNAK
     127 * ------                    ---------    -------            -------
     128 * Requested IP address      MUST NOT     MUST NOT           MUST NOT
     129 * IP address lease time     MUST         MUST (DHCPREQUEST) MUST NOT
     130 *                                        MUST NOT (DHCPINFORM)
     131 * Use 'file'/'sname' fields MAY          MAY                MUST NOT
     132 * DHCP message type         DHCPOFFER    DHCPACK            DHCPNAK
     133 * Parameter request list    MUST NOT     MUST NOT           MUST NOT
     134 * Message                   SHOULD       SHOULD             SHOULD
     135 * Client identifier         MUST NOT     MUST NOT           MAY
     136 * Vendor class identifier   MAY          MAY                MAY
     137 * Server identifier         MUST         MUST               MUST
     138 * Maximum message size      MUST NOT     MUST NOT           MUST NOT
     139 * All others                MAY          MAY                MUST NOT
     140 */
    63141static BOOTPClient *find_addr(PNATState pData, struct in_addr *paddr, const uint8_t *macaddr)
    64142{
     
    80158}
    81159
    82 static void dhcp_decode(const uint8_t *buf, int size,
    83                         int *pmsg_type, struct in_addr *req_ip)
    84 {
    85     const uint8_t *p, *p_end;
    86     int len, tag;
    87 
    88     *pmsg_type = 0;
    89 
    90     p = buf;
    91     p_end = buf + size;
    92     if (size < 5)
    93         return;
    94     if (memcmp(p, rfc1533_cookie, 4) != 0)
    95         return;
    96     p += 4;
    97     while (p < p_end)
    98     {
    99         tag = p[0];
    100         if (tag == RFC1533_PAD)
    101             p++;
    102         else if (tag == RFC1533_END)
    103             break;
    104         else
    105         {
    106             p++;
    107             if (p >= p_end)
    108                 break;
    109             len = *p++;
    110             Log(("dhcp: tag=0x%02x len=%d\n", tag, len));
    111 
    112             switch(tag)
    113             {
    114                 case RFC2132_REQ_ADDR:
    115                     if (len >= 4)
    116                         *req_ip = *(struct in_addr*)p;
    117                     break;
    118                 case RFC2132_MSG_TYPE:
    119                     if (len >= 1)
    120                         *pmsg_type = p[0];
    121                     break;
    122                 default:
    123                     break;
    124             }
    125             p += len;
    126         }
    127     }
    128 }
    129 
    130 static void bootp_reply(PNATState pData, struct mbuf *m0)
    131 {
    132     BOOTPClient *bc;
    133     struct mbuf *m; /* XXX: @todo vasily - it'd be better to reuse this mbuf here */
    134     struct bootp_t *bp = mtod(m0, struct bootp_t *);
     160static struct mbuf *dhcp_create_msg(PNATState pData, struct bootp_t *bp, struct mbuf *m, uint8_t type)
     161{
     162    struct bootp_t *rbp;
    135163    struct ethhdr *eh;
    136     struct bootp_t *rbp;
    137     struct sockaddr_in saddr, daddr;
    138     int dhcp_msg_type, val;
    139164    uint8_t *q;
    140     struct in_addr requested_ip; /* the requested IP in DHCPREQUEST */
    141     int send_nak = 0;
     165
     166    rbp = mtod(m, struct bootp_t *);
     167    memset(rbp, 0, sizeof(struct bootp_t));
     168    eh = mtod(m, struct ethhdr *);
     169    memcpy(eh->h_source, bp->bp_hwaddr, ETH_ALEN); /* XXX: if_encap just swap source with dest*/
     170    m->m_data += if_maxlinkhdr; /*reserve ether header */
     171    rbp = mtod(m, struct bootp_t *);
     172    rbp->bp_op = BOOTP_REPLY;
     173    rbp->bp_xid = bp->bp_xid; /* see table 3 of rfc2131*/
     174    rbp->flags = bp->flags;
     175    rbp->bp_giaddr.s_addr = bp->bp_giaddr.s_addr;
     176#if 0 /*check flags*/
     177    saddr.sin_port = htons(BOOTP_SERVER);
     178    daddr.sin_port = htons(BOOTP_CLIENT);
     179#endif
     180    rbp->bp_htype = 1;
     181    rbp->bp_hlen = 6;
     182    memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6);
     183
     184    memcpy(rbp->bp_vend, rfc1533_cookie, 4); /* cookie */
     185    q = rbp->bp_vend;
     186    q += 4;
     187    *q++ = RFC2132_MSG_TYPE;
     188    *q++ = 1;
     189    *q++ = type;
     190
     191    return m;
     192}
     193
     194static int dhcp_do_ack_offer(PNATState pData, struct mbuf *m, BOOTPClient *bc, int is_from_request)
     195{
     196    int off = 0;
     197    struct bootp_t *rbp = NULL;
     198    uint8_t *q;
     199    struct in_addr saddr;
     200    int val;
     201
     202    struct dns_entry *de = NULL;
     203    struct dns_domain_entry *dd = NULL;
     204    int added = 0;
     205    uint8_t *q_dns_header = NULL;
     206    uint32_t lease_time = htonl(LEASE_TIME);
     207    uint32_t netmask = htonl(pData->netmask);
     208
     209    rbp = mtod(m, struct bootp_t *);
     210    q = &rbp->bp_vend[0];
     211    q += 7; /* !cookie rfc 2132 + TYPE*/
     212
     213    /*DHCP Offer specific*/
     214    if (   tftp_prefix
     215        && RTDirExists(tftp_prefix)
     216        && bootp_filename)
     217        RTStrPrintf((char*)rbp->bp_file, sizeof(rbp->bp_file), "%s", bootp_filename);
     218
     219    Log(("NAT: DHCP: bp_file:%s\n", &rbp->bp_file));
     220    /* Address/port of the DHCP server. */
     221    rbp->bp_yiaddr = bc->addr; /* Client IP address */
     222    Log(("NAT: DHCP: bp_yiaddr:%R[IP4]\n", &rbp->bp_yiaddr));
     223    rbp->bp_siaddr = pData->tftp_server; /* Next Server IP address, i.e. TFTP */
     224    Log(("NAT: DHCP: bp_siaddr:%R[IP4]\n", &rbp->bp_siaddr));
     225    if (is_from_request)
     226    {
     227        rbp->bp_ciaddr.s_addr = bc->addr.s_addr; /* Client IP address */
     228    }
     229#ifndef VBOX_WITH_NAT_SERVICE
     230    saddr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
     231#else
     232    saddr.s_addr = special_addr.s_addr;
     233#endif
     234    Log(("NAT: DHCP: s_addr:%R[IP4]\n", &saddr));
    142235
    143236#define FILL_BOOTP_EXT(q, tag, len, pvalue)                     \
     
    159252    }while(0)
    160253
     254   
     255   
     256    FILL_BOOTP_EXT(q, RFC1533_NETMASK, 4, &netmask);
     257    FILL_BOOTP_EXT(q, RFC1533_GATEWAY, 4, &saddr);
     258   
     259    if (pData->use_dns_proxy)
     260    {
     261        uint32_t addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS);
     262        FILL_BOOTP_EXT(q, RFC1533_DNS, 4, &addr);
     263        goto skip_dns_servers;
     264    }
     265   
     266    if (!TAILQ_EMPTY(&pData->dns_list_head))
     267    {
     268        de = TAILQ_LAST(&pData->dns_list_head, dns_list_head);
     269        q_dns_header = q;
     270        FILL_BOOTP_EXT(q, RFC1533_DNS, 4, &de->de_addr.s_addr);
     271    }
     272   
     273    TAILQ_FOREACH_REVERSE(de, &pData->dns_list_head, dns_list_head, de_list)
     274    {
     275        if (TAILQ_LAST(&pData->dns_list_head, dns_list_head) == de)
     276            continue; /* first value with head we've ingected before */
     277        FILL_BOOTP_APP(q_dns_header, q, RFC1533_DNS, 4, &de->de_addr.s_addr);
     278    }
     279
     280skip_dns_servers:
     281    if (LIST_EMPTY(&pData->dns_domain_list_head))
     282    {
     283            /* Microsoft dhcp client doen't like domain-less dhcp and trimmed packets*/
     284            /* dhcpcd client very sad if no domain name is passed */
     285            FILL_BOOTP_EXT(q, RFC1533_DOMAINNAME, 1, " ");
     286    }
     287    if (pData->fPassDomain)
     288    {
     289        LIST_FOREACH(dd, &pData->dns_domain_list_head, dd_list)
     290        {
     291           
     292            if (dd->dd_pszDomain == NULL)
     293                continue;
     294            /* never meet valid separator here in RFC1533*/
     295            if (added != 0)
     296                FILL_BOOTP_EXT(q, RFC1533_DOMAINNAME, 1, ",");
     297            else
     298                added = 1;
     299            val = (int)strlen(dd->dd_pszDomain);
     300            FILL_BOOTP_EXT(q, RFC1533_DOMAINNAME, val, dd->dd_pszDomain);
     301        }
     302    }
     303   
     304    FILL_BOOTP_EXT(q, RFC2132_LEASE_TIME, 4, &lease_time);
     305   
     306    if (*slirp_hostname)
     307    {
     308        val = (int)strlen(slirp_hostname);
     309        FILL_BOOTP_EXT(q, RFC1533_HOSTNAME, val, slirp_hostname);
     310    }
     311    return q - rbp->bp_vend; /*return offset */
     312}
     313
     314static int dhcp_send_nack(PNATState pData, struct bootp_t *bp, BOOTPClient *bc, struct mbuf *m)
     315{
     316    struct bootp_t *rbp;
     317    uint8_t *q = NULL;
     318    rbp = mtod(m, struct bootp_t *);
     319
     320    dhcp_create_msg(pData, bp, m, DHCPNAK);
     321   
     322    return 7;
     323}
     324static int dhcp_send_ack(PNATState pData, struct bootp_t *bp, BOOTPClient *bc, struct mbuf *m, int is_from_request)
     325{
     326    struct bootp_t *rbp;
     327    int off = 0; /* boot_reply will fill general options and add END before sending response*/
     328
     329    dhcp_create_msg(pData, bp, m, DHCPACK);
     330    off = dhcp_do_ack_offer(pData, m, bc, is_from_request);
     331    return off;
     332}
     333static int dhcp_send_offer(PNATState pData, struct bootp_t *bp, BOOTPClient *bc, struct mbuf *m)
     334{
     335    struct bootp_t *rbp;
     336    int off = 0; /* boot_reply will fill general options and add END before sending response*/
     337
     338    dhcp_create_msg(pData, bp, m, DHCPOFFER);
     339    off = dhcp_do_ack_offer(pData, m, bc, 0);
     340    return off;
     341}
     342
     343/**
     344 *  decoding client messages RFC2131 (4.3.6)
     345 *  ---------------------------------------------------------------------
     346 *  |              |INIT-REBOOT  |SELECTING    |RENEWING     |REBINDING |
     347 *  ---------------------------------------------------------------------
     348 *  |broad/unicast |broadcast    |broadcast    |unicast      |broadcast |
     349 *  |server-ip     |MUST NOT     |MUST         |MUST NOT     |MUST NOT  |
     350 *  |requested-ip  |MUST         |MUST         |MUST NOT     |MUST NOT  |
     351 *  |ciaddr        |zero         |zero         |IP address   |IP address|
     352 *  ---------------------------------------------------------------------
     353 *
     354 */
     355enum DHCP_REQUEST_STATES{INIT_REBOOT, SELECTING, RENEWING, REBINDING, NONE};
     356static int dhcp_decode_request(PNATState pData, struct bootp_t *bp, const uint8_t *buf, int size, struct mbuf *m)
     357{
     358    BOOTPClient *bc;
     359    struct in_addr daddr;
     360    int off;
     361    uint8_t *opt;
     362    uint8_t *req_ip;
     363    uint8_t *server_ip;
     364    enum DHCP_REQUEST_STATES dhcp_stat = NONE;
     365    /*need to understand which type of request we get */
     366    req_ip = dhcp_find_option(&bp->bp_vend[0], RFC2132_REQ_ADDR);
     367    server_ip = dhcp_find_option(&bp->bp_vend[0], RFC2132_SRV_ID);
     368
     369    bc = find_addr(pData, &daddr, bp->bp_hwaddr);
     370    if (!bc)
     371    {
     372         LogRel(("NAT: DHCP no IP address left\n"));
     373         Log(("no address left\n"));
     374         return -1;
     375    }
     376    LogRel(("NAT: flags:%x sec:%x\n", bp->flags, bp->bp_secs));
     377    if (server_ip != NULL)
     378    {
     379        /*selecting*/
     380        dhcp_stat = SELECTING;
     381        Assert((bp->bp_ciaddr.s_addr == INADDR_ANY));
     382        Assert((*(uint32_t *)(req_ip + 2) == bc->addr.s_addr)); /*the same address as in offer*/
     383        Assert((bp->bp_xid == bc->xid));
     384    }
     385    else
     386    {
     387        if (req_ip != NULL)
     388        {
     389            /* init-reboot */
     390            dhcp_stat = INIT_REBOOT;
     391        }
     392        else
     393        {
     394            if (bp->flags & DHCP_FLAGS_B)
     395                dhcp_stat = RENEWING;
     396            else
     397                dhcp_stat = REBINDING; /*??rebinding??*/
     398        }
     399    }
     400        /*?? renewing ??*/
     401    if(dhcp_stat == RENEWING){
     402        Assert((   server_ip == NULL
     403            && req_ip == NULL
     404            && bp->bp_ciaddr.s_addr != INADDR_ANY));
     405        if (bc != NULL)
     406        {
     407            Assert((bc->addr.s_addr == bp->bp_ciaddr.s_addr));
     408            /*if it already here well just do ack, we aren't aware of dhcp time expiration*/
     409        }
     410        else
     411        {
     412           if ((bp->bp_ciaddr.s_addr & pData->netmask) != special_addr.s_addr)
     413           {
     414                off = dhcp_send_nack(pData, bp, bc, m);
     415                return off;
     416           }
     417           bc = alloc_addr(pData);
     418           if (bc == NULL)
     419           {
     420               LogRel(("NAT: can't alloc address. RENEW has been silently ignored\n"));
     421               return -1;
     422           }
     423           Assert((bp->bp_hlen == ETH_ALEN));
     424           memcpy(bc->macaddr, bp->bp_hwaddr, bp->bp_hlen);
     425           bc->addr.s_addr = bp->bp_ciaddr.s_addr; /* @todo change releasing */
     426        }
     427    }
     428    Assert((dhcp_stat != NONE));
     429    off = dhcp_send_ack(pData, bp, bc, m, 1);/*@todo when need send NACK */
     430    return off;
     431}
     432
     433static int dhcp_decode_discover(PNATState pData, struct bootp_t *bp, const uint8_t *buf, int size, int flag, struct mbuf *m)
     434{
     435    BOOTPClient *bc;
     436    struct in_addr daddr;
     437    int off;
     438    /* flag == 1 discover */
     439    if (flag == 1)
     440    {
     441        bc = find_addr(pData, &daddr, bp->bp_hwaddr);
     442        if (!bc)
     443        {
     444            bc = get_new_addr(pData, &daddr);
     445            if (!bc)
     446            {
     447                LogRel(("NAT: DHCP no IP address left\n"));
     448                Log(("no address left\n"));
     449                return -1;
     450            }
     451            memcpy(bc->macaddr, bp->bp_hwaddr, 6);
     452        }
     453        bc->xid = bp->bp_xid;
     454        /*bc isn't NULL */
     455        off = dhcp_send_offer(pData, bp, bc, m);
     456        return off;
     457    }
     458    else
     459    {
     460        /* flag == 0 inform */
     461        bc = find_addr(pData, &daddr, bp->bp_hwaddr);
     462        if (bc == NULL)
     463        {
     464            LogRel(("NAT: DHCP Inform was ignored no boot client was found\n"));
     465            return -1;
     466        }
     467        off = dhcp_send_ack(pData, bp, bc, m, 0);
     468        return off;
     469    }
     470    return -1;
     471}
     472
     473static int dhcp_decode_release(PNATState pData, struct bootp_t *bp, const uint8_t *buf, int size, int flag)
     474{
     475    return -1;
     476}
     477/**
     478 * fields for discovering t
     479 * Field      DHCPDISCOVER          DHCPREQUEST           DHCPDECLINE,
     480 *            DHCPINFORM                                  DHCPRELEASE
     481 * -----      ------------          -----------           -----------
     482 * 'op'       BOOTREQUEST           BOOTREQUEST           BOOTREQUEST
     483 * 'htype'    (From "Assigned Numbers" RFC)
     484 * 'hlen'     (Hardware address length in octets)
     485 * 'hops'     0                     0                     0
     486 * 'xid'      selected by client    'xid' from server     selected by
     487 *                                  DHCPOFFER message     client
     488 * 'secs'     0 or seconds since    0 or seconds since    0
     489 *            DHCP process started  DHCP process started
     490 * 'flags'    Set 'BROADCAST'       Set 'BROADCAST'       0
     491 *            flag if client        flag if client
     492 *            requires broadcast    requires broadcast
     493 *            reply                 reply
     494 * 'ciaddr'   0 (DHCPDISCOVER)      0 or client's         0 (DHCPDECLINE)
     495 *            client's              network address       client's network
     496 *            network address       (BOUND/RENEW/REBIND)  address
     497 *            (DHCPINFORM)                                (DHCPRELEASE)
     498 * 'yiaddr'   0                     0                     0
     499 * 'siaddr'   0                     0                     0
     500 * 'giaddr'   0                     0                     0
     501 * 'chaddr'   client's hardware     client's hardware     client's hardware
     502 *            address               address               address
     503 * 'sname'    options, if           options, if           (unused)
     504 *            indicated in          indicated in
     505 *            'sname/file'          'sname/file'
     506 *            option; otherwise     option; otherwise
     507 *            unused                unused
     508 * 'file'     options, if           options, if           (unused)
     509 *            indicated in          indicated in
     510 *            'sname/file'          'sname/file'
     511 *            option; otherwise     option; otherwise
     512 *            unused                unused
     513 * 'options'  options               options               (unused)
     514 * Requested IP address       MAY           MUST (in         MUST
     515 *                            (DISCOVER)    SELECTING or     (DHCPDECLINE),
     516 *                            MUST NOT      INIT-REBOOT)     MUST NOT
     517 *                            (INFORM)      MUST NOT (in     (DHCPRELEASE)
     518 *                                          BOUND or
     519 *                                          RENEWING)
     520 * IP address lease time      MAY           MAY              MUST NOT
     521 *                            (DISCOVER)
     522 *                            MUST NOT
     523 *                            (INFORM)
     524 * Use 'file'/'sname' fields  MAY           MAY              MAY
     525 * DHCP message type          DHCPDISCOVER/ DHCPREQUEST      DHCPDECLINE/
     526 *                            DHCPINFORM                     DHCPRELEASE
     527 * Client identifier          MAY           MAY              MAY
     528 * Vendor class identifier    MAY           MAY              MUST NOT
     529 * Server identifier          MUST NOT      MUST (after      MUST
     530 *                                          SELECTING)
     531 *                                          MUST NOT (after
     532 *                                          INIT-REBOOT,
     533 *                                          BOUND, RENEWING
     534 *                                          or REBINDING)
     535 * Parameter request list     MAY           MAY              MUST NOT
     536 * Maximum message size       MAY           MAY              MUST NOT
     537 * Message                    SHOULD NOT    SHOULD NOT       SHOULD
     538 * Site-specific              MAY           MAY              MUST NOT
     539 * All others                 MAY           MAY              MUST NOT
     540 *
     541 */
     542static void dhcp_decode(PNATState pData, struct bootp_t *bp, const uint8_t *buf, int size)
     543{
     544    const uint8_t *p, *p_end;
     545    int rc;
     546    int pmsg_type;
     547    struct in_addr req_ip;
     548    int flag = 0;
     549    int len, tag;
     550    struct mbuf *m = NULL;
     551
     552    pmsg_type = 0;
     553
     554    p = buf;
     555    p_end = buf + size;
     556    if (size < 5)
     557        return;
     558    if (memcmp(p, rfc1533_cookie, 4) != 0)
     559        return;
     560    p = dhcp_find_option(bp->bp_vend, RFC2132_MSG_TYPE);
     561    Assert(p);
     562    if (p == NULL)
     563        return;
     564    if ((m = m_get(pData)) == NULL)
     565    {
     566        LogRel(("NAT: can't alocate memory for response!\n"));
     567        return;
     568    }
     569    switch(*(p+2))
     570    {
     571        case DHCPDISCOVER:
     572            flag = 1;
     573            /**/
     574        case DHCPINFORM:
     575            rc = dhcp_decode_discover(pData, bp, buf, size, flag, m);
     576            Assert(rc > 0);
     577            goto reply;
     578        break;
     579        case DHCPREQUEST:
     580            rc = dhcp_decode_request(pData, bp, buf, size, m);
     581            Assert(rc > 0);
     582            goto reply;
     583        break;
     584        case DHCPRELEASE:
     585            flag = 1;
     586#if 0
     587        case DHCPDECLINE:
     588#endif
     589            rc = dhcp_decode_release(pData, bp, buf, size, flag);
     590            Assert(rc > 0);
     591            goto reply;
     592        break;
     593        default:
     594            AssertMsgFailed(("unsupported DHCP message type"));
     595    }
     596    return;
     597reply:
     598    Assert(m);
     599    if (rc < 0)
     600    {
     601        /*silently ignore*/
     602        m_free(pData, m);
     603        return;
     604    }
     605    bootp_reply(pData, m, rc, bp->flags);
     606    return;
     607}
     608
     609static void bootp_reply(PNATState pData, struct mbuf *m, int off, uint16_t flags)
     610{
     611#if 0
     612    BOOTPClient *bc;
     613    struct mbuf *m; /* XXX: @todo vasily - it'd be better to reuse this mbuf here */
     614    struct bootp_t *bp = mtod(m0, struct bootp_t *);
     615    struct bootp_t *rbp;
     616    struct sockaddr_in saddr, daddr;
     617    int dhcp_msg_type, val;
     618    uint8_t *q;
     619    struct in_addr requested_ip; /* the requested IP in DHCPREQUEST */
     620    int send_nak = 0;
     621
    161622    /* extract exact DHCP msg type */
    162623    requested_ip.s_addr = 0xffffffff;
    163     dhcp_decode(bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type, &requested_ip);
     624    dhcp_decode(bp, bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type, &requested_ip);
    164625    Log(("bootp packet op=%d msgtype=%d\n", bp->bp_op, dhcp_msg_type));
    165626
     
    181642        return;
    182643
    183     if ((m = m_get(pData)) == NULL)
    184         return;
    185     eh = mtod(m, struct ethhdr *);
    186     memcpy(eh->h_source, bp->bp_hwaddr, ETH_ALEN); /* XXX: if_encap just swap source with dest*/
    187     m->m_data += if_maxlinkhdr; /*reserve ether header */
    188     rbp = mtod(m, struct bootp_t *);
    189     memset(rbp, 0, sizeof(struct bootp_t));
    190644
    191645    if (dhcp_msg_type == DHCPDISCOVER)
    192646    {
    193647        /* Do not allocate a new lease for clients that forgot that they had a lease. */
    194         bc = find_addr(pData, &daddr.sin_addr, bp->bp_hwaddr);
    195         if (!bc)
    196         {
    197     new_addr:
    198             bc = get_new_addr(pData, &daddr.sin_addr);
    199             if (!bc)
    200             {
    201                 LogRel(("NAT: DHCP no IP address left\n"));
    202                 Log(("no address left\n"));
    203                 return;
    204             }
    205             memcpy(bc->macaddr, bp->bp_hwaddr, 6);
    206         }
    207     }
    208     else
    209     {
    210         bc = find_addr(pData, &daddr.sin_addr, bp->bp_hwaddr);
    211         if (!bc)
    212         {
    213             /* if never assigned, behaves as if it was already
    214                assigned (windows fix because it remembers its address) */
    215             goto new_addr;
    216         }
    217     }
    218 
    219     if (   tftp_prefix
    220         && RTDirExists(tftp_prefix)
    221         && bootp_filename)
    222         RTStrPrintf((char*)rbp->bp_file, sizeof(rbp->bp_file), "%s", bootp_filename);
    223 
    224     Log(("NAT: DHCP: bp_file:%s\n", &rbp->bp_file));
    225     /* Address/port of the DHCP server. */
    226 #ifndef VBOX_WITH_NAT_SERVICE
    227     saddr.sin_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
    228 #else
    229     saddr.sin_addr.s_addr = special_addr.s_addr;
    230 #endif
    231     Log(("NAT: DHCP: s_addr:%R[IP4]\n", &saddr.sin_addr));
    232 
    233     saddr.sin_port = htons(BOOTP_SERVER);
    234 
    235     daddr.sin_port = htons(BOOTP_CLIENT);
    236 
    237     rbp->bp_op = BOOTP_REPLY;
    238     rbp->bp_xid = bp->bp_xid;
    239     rbp->bp_htype = 1;
    240     rbp->bp_hlen = 6;
    241     memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6);
    242 
    243     rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
    244     Log(("NAT: DHCP: bp_yiaddr:%R[IP4]\n", &rbp->bp_yiaddr));
    245     rbp->bp_siaddr = pData->tftp_server; /* Next Server IP address, i.e. TFTP */
    246     Log(("NAT: DHCP: bp_siaddr:%R[IP4]\n", &rbp->bp_siaddr));
    247 
    248     q = rbp->bp_vend;
    249     memcpy(q, rfc1533_cookie, 4);
    250     q += 4;
    251 
    252     if (dhcp_msg_type == DHCPDISCOVER)
    253     {
    254         *q++ = RFC2132_MSG_TYPE;
    255         *q++ = 1;
    256         *q++ = DHCPOFFER;
    257648    }
    258649    else if (dhcp_msg_type == DHCPREQUEST)
     
    285676        (   dhcp_msg_type == DHCPDISCOVER
    286677         || dhcp_msg_type == DHCPREQUEST))
    287     {
    288         struct dns_entry *de = NULL;
    289         struct dns_domain_entry *dd = NULL;
    290         int added = 0;
    291         uint8_t *q_dns_header = NULL;
    292         uint32_t lease_time = htonl(LEASE_TIME);
    293         uint32_t netmask = htonl(pData->netmask);
    294 
    295         FILL_BOOTP_EXT(q, RFC1533_NETMASK, 4, &netmask);
    296         FILL_BOOTP_EXT(q, RFC1533_GATEWAY, 4, &saddr.sin_addr);
    297 
    298         if (pData->use_dns_proxy)
    299         {
    300             uint32_t addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS);
    301             FILL_BOOTP_EXT(q, RFC1533_DNS, 4, &addr);
    302             goto skip_dns_servers;
    303         }
    304 
    305         if (!TAILQ_EMPTY(&pData->dns_list_head))
    306         {
    307             de = TAILQ_LAST(&pData->dns_list_head, dns_list_head);
    308             q_dns_header = q;
    309             FILL_BOOTP_EXT(q, RFC1533_DNS, 4, &de->de_addr.s_addr);
    310         }
    311 
    312         TAILQ_FOREACH_REVERSE(de, &pData->dns_list_head, dns_list_head, de_list)
    313         {
    314             if (TAILQ_LAST(&pData->dns_list_head, dns_list_head) == de)
    315                 continue; /* first value with head we've ingected before */
    316             FILL_BOOTP_APP(q_dns_header, q, RFC1533_DNS, 4, &de->de_addr.s_addr);
    317         }
    318 
    319 skip_dns_servers:
    320         if (LIST_EMPTY(&pData->dns_domain_list_head))
    321         {
    322                 /* Microsoft dhcp client doen't like domain-less dhcp and trimmed packets*/
    323                 /* dhcpcd client very sad if no domain name is passed */
    324                 FILL_BOOTP_EXT(q, RFC1533_DOMAINNAME, 1, " ");
    325         }
    326         if (pData->fPassDomain)
    327         {
    328             LIST_FOREACH(dd, &pData->dns_domain_list_head, dd_list)
    329             {
    330                
    331                 if (dd->dd_pszDomain == NULL)
    332                     continue;
    333                 /* never meet valid separator here in RFC1533*/
    334                 if (added != 0)
    335                     FILL_BOOTP_EXT(q, RFC1533_DOMAINNAME, 1, ",");
    336                 else
    337                     added = 1;
    338                 val = (int)strlen(dd->dd_pszDomain);
    339                 FILL_BOOTP_EXT(q, RFC1533_DOMAINNAME, val, dd->dd_pszDomain);
    340             }
    341         }
    342 
    343         FILL_BOOTP_EXT(q, RFC2132_LEASE_TIME, 4, &lease_time);
    344 
    345         if (*slirp_hostname)
    346         {
    347             val = (int)strlen(slirp_hostname);
    348             FILL_BOOTP_EXT(q, RFC1533_HOSTNAME, val, slirp_hostname);
    349         }
    350     }
    351     *q++ = RFC1533_END;
     678#endif
     679    struct sockaddr_in saddr, daddr;
     680    struct bootp_t *rbp = NULL;
     681    uint8_t *q = NULL;
     682    int nack;
     683    rbp = mtod(m, struct bootp_t *);
     684    Assert((m));
     685    Assert((rbp));
     686    q = rbp->bp_vend;
     687    nack = (q[6] == DHCPNAK);
     688    q += off;
     689
     690#ifndef VBOX_WITH_NAT_SERVICE
     691    saddr.sin_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
     692#else
     693    saddr.sin_addr.s_addr = special_addr.s_addr;
     694#endif
     695
     696    FILL_BOOTP_EXT(q, RFC2132_SRV_ID, 4, &saddr.sin_addr);
     697
     698   
     699    *q++ = RFC1533_END; /*end of message */
     700   
    352701
    353702    m->m_len = sizeof(struct bootp_t)
     
    356705    m->m_data += sizeof(struct udphdr)
    357706               + sizeof(struct ip);
    358     /* Reply to the broadcast address, as some clients perform paranoid checks. */
    359     daddr.sin_addr.s_addr = INADDR_BROADCAST;
     707    if ((flags & DHCP_FLAGS_B) || nack != 0)
     708        daddr.sin_addr.s_addr = INADDR_BROADCAST;
     709    else
     710        daddr.sin_addr.s_addr = rbp->bp_yiaddr.s_addr; /*unicast requested by client*/
     711    saddr.sin_port = htons(BOOTP_SERVER);
     712    daddr.sin_port = htons(BOOTP_CLIENT);
    360713    udp_output2(pData, NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
    361714}
     
    366719
    367720    if (bp->bp_op == BOOTP_REQUEST)
    368         bootp_reply(pData, m);
    369 }
     721    {
     722        dhcp_decode(pData, bp, bp->bp_vend, DHCP_OPT_LEN);
     723    }
     724}
  • trunk/src/VBox/Devices/Network/slirp/bootp.h

    r16214 r22101  
    7474#define DHCPNAK                 6
    7575#define DHCPRELEASE             7
     76#define DHCPINFORM              8
    7677
    7778#define RFC1533_VENDOR_MAJOR    0
     
    103104    uint32_t       bp_xid;
    104105    uint16_t       bp_secs;
    105     uint16_t       unused;
     106    uint16_t       flags;
    106107    struct in_addr bp_ciaddr;
    107108    struct in_addr bp_yiaddr;
     
    113114    uint8_t        bp_vend[DHCP_OPT_LEN];
    114115};
    115 
     116#define DHCP_FLAGS_B (1<<15)
    116117struct bootp_ext
    117118{
  • trunk/src/VBox/Devices/Network/slirp/slirp_state.h

    r22024 r22101  
    3838typedef struct
    3939{
     40    uint32_t xid;
    4041    bool allocated;
    4142    uint8_t macaddr[6];
    4243    struct in_addr addr;
     44    int number;
    4345} BOOTPClient;
    4446
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette