Annotation of embedaddon/dnsmasq/src/edns0.c, revision 1.1.1.3

1.1.1.3 ! misho       1: /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
1.1       misho       2: 
                      3:    This program is free software; you can redistribute it and/or modify
                      4:    it under the terms of the GNU General Public License as published by
                      5:    the Free Software Foundation; version 2 dated June, 1991, or
                      6:    (at your option) version 3 dated 29 June, 2007.
                      7:  
                      8:    This program is distributed in the hope that it will be useful,
                      9:    but WITHOUT ANY WARRANTY; without even the implied warranty of
                     10:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     11:    GNU General Public License for more details.
                     12:      
                     13:    You should have received a copy of the GNU General Public License
                     14:    along with this program.  If not, see <http://www.gnu.org/licenses/>.
                     15: */
                     16: 
                     17: #include "dnsmasq.h"
                     18: 
                     19: unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t  *len, unsigned char **p, int *is_sign, int *is_last)
                     20: {
                     21:   /* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it. 
                     22:      also return length of pseudoheader in *len and pointer to the UDP size in *p
                     23:      Finally, check to see if a packet is signed. If it is we cannot change a single bit before
                     24:      forwarding. We look for TSIG in the addition section, and TKEY queries (for GSS-TSIG) */
                     25:   
                     26:   int i, arcount = ntohs(header->arcount);
                     27:   unsigned char *ansp = (unsigned char *)(header+1);
                     28:   unsigned short rdlen, type, class;
                     29:   unsigned char *ret = NULL;
                     30: 
                     31:   if (is_sign)
                     32:     {
                     33:       *is_sign = 0;
                     34: 
                     35:       if (OPCODE(header) == QUERY)
                     36:        {
                     37:          for (i = ntohs(header->qdcount); i != 0; i--)
                     38:            {
                     39:              if (!(ansp = skip_name(ansp, header, plen, 4)))
                     40:                return NULL;
                     41:              
                     42:              GETSHORT(type, ansp); 
                     43:              GETSHORT(class, ansp);
                     44:              
                     45:              if (class == C_IN && type == T_TKEY)
                     46:                *is_sign = 1;
                     47:            }
                     48:        }
                     49:     }
                     50:   else
                     51:     {
                     52:       if (!(ansp = skip_questions(header, plen)))
                     53:        return NULL;
                     54:     }
                     55:     
                     56:   if (arcount == 0)
                     57:     return NULL;
                     58:   
                     59:   if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount), header, plen)))
                     60:     return NULL; 
                     61:   
                     62:   for (i = 0; i < arcount; i++)
                     63:     {
                     64:       unsigned char *save, *start = ansp;
                     65:       if (!(ansp = skip_name(ansp, header, plen, 10)))
                     66:        return NULL; 
                     67: 
                     68:       GETSHORT(type, ansp);
                     69:       save = ansp;
                     70:       GETSHORT(class, ansp);
                     71:       ansp += 4; /* TTL */
                     72:       GETSHORT(rdlen, ansp);
                     73:       if (!ADD_RDLEN(header, ansp, plen, rdlen))
                     74:        return NULL;
                     75:       if (type == T_OPT)
                     76:        {
                     77:          if (len)
                     78:            *len = ansp - start;
                     79: 
                     80:          if (p)
                     81:            *p = save;
                     82:          
                     83:          if (is_last)
                     84:            *is_last = (i == arcount-1);
                     85: 
                     86:          ret = start;
                     87:        }
                     88:       else if (is_sign && 
                     89:               i == arcount - 1 && 
                     90:               class == C_ANY && 
                     91:               type == T_TSIG)
                     92:        *is_sign = 1;
                     93:     }
                     94:   
                     95:   return ret;
                     96: }
                     97:  
                     98: 
                     99: /* replace == 2 ->delete existing option only. */
                    100: size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, 
                    101:                        unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do, int replace)
                    102: { 
                    103:   unsigned char *lenp, *datap, *p, *udp_len, *buff = NULL;
                    104:   int rdlen = 0, is_sign, is_last;
                    105:   unsigned short flags = set_do ? 0x8000 : 0, rcode = 0;
                    106: 
                    107:   p = find_pseudoheader(header, plen, NULL, &udp_len, &is_sign, &is_last);
                    108:   
                    109:   if (is_sign)
                    110:     return plen;
                    111: 
                    112:   if (p)
                    113:     {
                    114:       /* Existing header */
                    115:       int i;
                    116:       unsigned short code, len;
                    117: 
                    118:       p = udp_len;
                    119:       GETSHORT(udp_sz, p);
                    120:       GETSHORT(rcode, p);
                    121:       GETSHORT(flags, p);
                    122: 
                    123:       if (set_do)
                    124:        {
                    125:          p -= 2;
                    126:          flags |= 0x8000;
                    127:          PUTSHORT(flags, p);
                    128:        }
                    129: 
                    130:       lenp = p;
                    131:       GETSHORT(rdlen, p);
                    132:       if (!CHECK_LEN(header, p, plen, rdlen))
                    133:        return plen; /* bad packet */
                    134:       datap = p;
                    135: 
                    136:        /* no option to add */
                    137:       if (optno == 0)
                    138:        return plen;
                    139:          
                    140:       /* check if option already there */
                    141:       for (i = 0; i + 4 < rdlen;)
                    142:        {
                    143:          GETSHORT(code, p);
                    144:          GETSHORT(len, p);
                    145:          
                    146:          /* malformed option, delete the whole OPT RR and start again. */
1.1.1.2   misho     147:          if (i + 4 + len > rdlen)
1.1       misho     148:            {
                    149:              rdlen = 0;
                    150:              is_last = 0;
                    151:              break;
                    152:            }
                    153:          
                    154:          if (code == optno)
                    155:            {
                    156:              if (replace == 0)
                    157:                return plen;
                    158: 
                    159:              /* delete option if we're to replace it. */
                    160:              p -= 4;
                    161:              rdlen -= len + 4;
1.1.1.2   misho     162:              memmove(p, p+len+4, rdlen - i);
1.1       misho     163:              PUTSHORT(rdlen, lenp);
                    164:              lenp -= 2;
                    165:            }
                    166:          else
                    167:            {
                    168:              p += len;
                    169:              i += len + 4;
                    170:            }
                    171:        }
                    172: 
                    173:       /* If we're going to extend the RR, it has to be the last RR in the packet */
                    174:       if (!is_last)
                    175:        {
                    176:          /* First, take a copy of the options. */
                    177:          if (rdlen != 0 && (buff = whine_malloc(rdlen)))
                    178:            memcpy(buff, datap, rdlen);       
                    179:          
                    180:          /* now, delete OPT RR */
1.1.1.3 ! misho     181:          plen = rrfilter(header, plen, RRFILTER_EDNS0);
1.1       misho     182:          
                    183:          /* Now, force addition of a new one */
                    184:          p = NULL;       
                    185:        }
                    186:     }
                    187:   
                    188:   if (!p)
                    189:     {
                    190:       /* We are (re)adding the pseudoheader */
                    191:       if (!(p = skip_questions(header, plen)) ||
                    192:          !(p = skip_section(p, 
                    193:                             ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount), 
                    194:                             header, plen)))
1.1.1.2   misho     195:       {
                    196:        free(buff);
1.1       misho     197:        return plen;
1.1.1.2   misho     198:       }
                    199:       if (p + 11 > limit)
                    200:       {
                    201:         free(buff);
                    202:         return plen; /* Too big */
                    203:       }
1.1       misho     204:       *p++ = 0; /* empty name */
                    205:       PUTSHORT(T_OPT, p);
                    206:       PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
                    207:       PUTSHORT(rcode, p);    /* extended RCODE and version */
                    208:       PUTSHORT(flags, p); /* DO flag */
                    209:       lenp = p;
                    210:       PUTSHORT(rdlen, p);    /* RDLEN */
                    211:       datap = p;
                    212:       /* Copy back any options */
                    213:       if (buff)
                    214:        {
1.1.1.2   misho     215:           if (p + rdlen > limit)
                    216:           {
                    217:             free(buff);
                    218:             return plen; /* Too big */
                    219:           }
1.1       misho     220:          memcpy(p, buff, rdlen);
                    221:          free(buff);
                    222:          p += rdlen;
                    223:        }
1.1.1.2   misho     224:       
                    225:       /* Only bump arcount if RR is going to fit */ 
                    226:       if (((ssize_t)optlen) <= (limit - (p + 4)))
                    227:        header->arcount = htons(ntohs(header->arcount) + 1);
1.1       misho     228:     }
                    229:   
                    230:   if (((ssize_t)optlen) > (limit - (p + 4)))
                    231:     return plen; /* Too big */
                    232:   
                    233:   /* Add new option */
                    234:   if (optno != 0 && replace != 2)
                    235:     {
1.1.1.2   misho     236:       if (p + 4 > limit)
                    237:        return plen; /* Too big */
1.1       misho     238:       PUTSHORT(optno, p);
                    239:       PUTSHORT(optlen, p);
1.1.1.2   misho     240:       if (p + optlen > limit)
                    241:        return plen; /* Too big */
1.1       misho     242:       memcpy(p, opt, optlen);
                    243:       p += optlen;  
                    244:       PUTSHORT(p - datap, lenp);
                    245:     }
                    246:   return p - (unsigned char *)header;
                    247: }
                    248: 
                    249: size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit)
                    250: {
                    251:   return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1, 0);
                    252: }
                    253: 
                    254: static unsigned char char64(unsigned char c)
                    255: {
                    256:   return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[c & 0x3f];
                    257: }
                    258: 
                    259: static void encoder(unsigned char *in, char *out)
                    260: {
                    261:   out[0] = char64(in[0]>>2);
                    262:   out[1] = char64((in[0]<<4) | (in[1]>>4));
                    263:   out[2] = char64((in[1]<<2) | (in[2]>>6));
                    264:   out[3] = char64(in[2]);
                    265: }
                    266: 
1.1.1.3 ! misho     267: /* OPT_ADD_MAC = MAC is added (if available)
        !           268:    OPT_ADD_MAC + OPT_STRIP_MAC = MAC is replaced, if not available, it is only removed
        !           269:    OPT_STRIP_MAC = MAC is removed */
1.1.1.2   misho     270: static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit,
                    271:                             union mysockaddr *l3, time_t now, int *cacheablep)
1.1       misho     272: {
1.1.1.3 ! misho     273:   int replace = 0, maclen = 0;
1.1       misho     274:   unsigned char mac[DHCP_CHADDR_MAX];
1.1.1.3 ! misho     275:   char encode[18]; /* handle 6 byte MACs ONLY */
1.1       misho     276: 
1.1.1.3 ! misho     277:   if ((option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX)) && (maclen = find_mac(l3, mac, 1, now)) == 6)
1.1       misho     278:     {
1.1.1.3 ! misho     279:       if (option_bool(OPT_STRIP_MAC))
        !           280:         replace = 1;
        !           281:        *cacheablep = 0;
        !           282:     
        !           283:        if (option_bool(OPT_MAC_HEX))
        !           284:         print_mac(encode, mac, maclen);
        !           285:        else
        !           286:         {
        !           287:           encoder(mac, encode);
        !           288:           encoder(mac+3, encode+4);
        !           289:           encode[8] = 0;
        !           290:         }
1.1       misho     291:     }
1.1.1.3 ! misho     292:   else if (option_bool(OPT_STRIP_MAC))
        !           293:     replace = 2;
        !           294: 
        !           295:   if (replace != 0 || maclen == 6)
        !           296:     plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMDEVICEID, (unsigned char *)encode, strlen(encode), 0, replace);
1.1       misho     297: 
1.1.1.3 ! misho     298:   return plen;
1.1       misho     299: }
                    300: 
                    301: 
1.1.1.3 ! misho     302: /* OPT_ADD_MAC = MAC is added (if available)
        !           303:    OPT_ADD_MAC + OPT_STRIP_MAC = MAC is replaced, if not available, it is only removed
        !           304:    OPT_STRIP_MAC = MAC is removed */
1.1.1.2   misho     305: static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit,
                    306:                      union mysockaddr *l3, time_t now, int *cacheablep)
1.1       misho     307: {
1.1.1.3 ! misho     308:   int maclen = 0, replace = 0;
1.1       misho     309:   unsigned char mac[DHCP_CHADDR_MAX];
1.1.1.3 ! misho     310:     
        !           311:   if (option_bool(OPT_ADD_MAC) && (maclen = find_mac(l3, mac, 1, now)) != 0)
1.1.1.2   misho     312:     {
                    313:       *cacheablep = 0;
1.1.1.3 ! misho     314:       if (option_bool(OPT_STRIP_MAC))
        !           315:        replace = 1;
1.1.1.2   misho     316:     }
1.1.1.3 ! misho     317:   else if (option_bool(OPT_STRIP_MAC))
        !           318:     replace = 2;
1.1.1.2   misho     319:   
1.1.1.3 ! misho     320:   if (replace != 0 || maclen != 0)
        !           321:     plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, replace);
        !           322: 
1.1       misho     323:   return plen; 
                    324: }
                    325: 
                    326: struct subnet_opt {
                    327:   u16 family;
1.1.1.2   misho     328:   u8 source_netmask, scope_netmask; 
1.1       misho     329:   u8 addr[IN6ADDRSZ];
                    330: };
                    331: 
                    332: static void *get_addrp(union mysockaddr *addr, const short family) 
                    333: {
                    334:   if (family == AF_INET6)
                    335:     return &addr->in6.sin6_addr;
                    336: 
                    337:   return &addr->in.sin_addr;
                    338: }
                    339: 
1.1.1.2   misho     340: static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source, int *cacheablep)
1.1       misho     341: {
                    342:   /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
                    343:   
                    344:   int len;
1.1.1.2   misho     345:   void *addrp = NULL;
1.1       misho     346:   int sa_family = source->sa.sa_family;
1.1.1.2   misho     347:   int cacheable = 0;
                    348:   
1.1       misho     349:   opt->source_netmask = 0;
                    350:   opt->scope_netmask = 0;
1.1.1.2   misho     351:     
1.1       misho     352:   if (source->sa.sa_family == AF_INET6 && daemon->add_subnet6)
                    353:     {
                    354:       opt->source_netmask = daemon->add_subnet6->mask;
                    355:       if (daemon->add_subnet6->addr_used) 
                    356:        {
                    357:          sa_family = daemon->add_subnet6->addr.sa.sa_family;
                    358:          addrp = get_addrp(&daemon->add_subnet6->addr, sa_family);
1.1.1.2   misho     359:          cacheable = 1;
1.1       misho     360:        } 
                    361:       else 
                    362:        addrp = &source->in6.sin6_addr;
                    363:     }
                    364: 
                    365:   if (source->sa.sa_family == AF_INET && daemon->add_subnet4)
                    366:     {
                    367:       opt->source_netmask = daemon->add_subnet4->mask;
                    368:       if (daemon->add_subnet4->addr_used)
                    369:        {
                    370:          sa_family = daemon->add_subnet4->addr.sa.sa_family;
                    371:          addrp = get_addrp(&daemon->add_subnet4->addr, sa_family);
1.1.1.2   misho     372:          cacheable = 1; /* Address is constant */
1.1       misho     373:        } 
                    374:        else 
                    375:          addrp = &source->in.sin_addr;
                    376:     }
                    377:   
                    378:   opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
                    379:   
1.1.1.2   misho     380:   if (addrp && opt->source_netmask != 0)
1.1       misho     381:     {
                    382:       len = ((opt->source_netmask - 1) >> 3) + 1;
                    383:       memcpy(opt->addr, addrp, len);
                    384:       if (opt->source_netmask & 7)
                    385:        opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));
                    386:     }
1.1.1.2   misho     387:   else
                    388:     {
                    389:       cacheable = 1; /* No address ever supplied. */
                    390:       len = 0;
                    391:     }
                    392: 
                    393:   if (cacheablep)
                    394:     *cacheablep = cacheable;
1.1       misho     395:   
                    396:   return len + 4;
                    397: }
                    398:  
1.1.1.3 ! misho     399: /* OPT_CLIENT_SUBNET = client subnet is added
        !           400:    OPT_CLIENT_SUBNET + OPT_STRIP_ECS = client subnet is replaced
        !           401:    OPT_STRIP_ECS = client subnet is removed */
        !           402: static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit,
        !           403:                              union mysockaddr *source, int *cacheable)
1.1       misho     404: {
                    405:   /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
                    406:   
1.1.1.3 ! misho     407:   int replace = 0, len = 0;
1.1       misho     408:   struct subnet_opt opt;
                    409:   
1.1.1.3 ! misho     410:   if (option_bool(OPT_CLIENT_SUBNET))
        !           411:     {
        !           412:       if (option_bool(OPT_STRIP_ECS))
        !           413:        replace = 1;
        !           414:       len = calc_subnet_opt(&opt, source, cacheable);
        !           415:     }
        !           416:   else if (option_bool(OPT_STRIP_ECS))
        !           417:     replace = 2;
        !           418:   else
        !           419:     return plen;
        !           420: 
        !           421:   return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, replace);
1.1       misho     422: }
                    423: 
                    424: int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
                    425: {
                    426:   /* Section 9.2, Check that subnet option in reply matches. */
                    427:   
                    428:   int len, calc_len;
                    429:   struct subnet_opt opt;
                    430:   unsigned char *p;
                    431:   int code, i, rdlen;
                    432:   
1.1.1.2   misho     433:   calc_len = calc_subnet_opt(&opt, peer, NULL);
1.1       misho     434:    
1.1.1.2   misho     435:   if (!(p = skip_name(pseudoheader, header, plen, 10)))
                    436:     return 1;
                    437:   
                    438:   p += 8; /* skip UDP length and RCODE */
                    439:   
                    440:   GETSHORT(rdlen, p);
                    441:   if (!CHECK_LEN(header, p, plen, rdlen))
                    442:     return 1; /* bad packet */
                    443:   
                    444:   /* check if option there */
1.1       misho     445:    for (i = 0; i + 4 < rdlen; i += len + 4)
                    446:      {
                    447:        GETSHORT(code, p);
                    448:        GETSHORT(len, p);
                    449:        if (code == EDNS0_OPTION_CLIENT_SUBNET)
                    450:         {
                    451:           /* make sure this doesn't mismatch. */
                    452:           opt.scope_netmask = p[3];
                    453:           if (len != calc_len || memcmp(p, &opt, len) != 0)
                    454:             return 0;
                    455:         }
                    456:        p += len;
                    457:      }
                    458:    
                    459:    return 1;
                    460: }
                    461: 
1.1.1.3 ! misho     462: /* See https://docs.umbrella.com/umbrella-api/docs/identifying-dns-traffic for
        !           463:  * detailed information on packet formating.
        !           464:  */
        !           465: #define UMBRELLA_VERSION    1
        !           466: #define UMBRELLA_TYPESZ     2
        !           467: 
        !           468: #define UMBRELLA_ASSET      0x0004
        !           469: #define UMBRELLA_ASSETSZ    sizeof(daemon->umbrella_asset)
        !           470: #define UMBRELLA_ORG        0x0008
        !           471: #define UMBRELLA_ORGSZ      sizeof(daemon->umbrella_org)
        !           472: #define UMBRELLA_IPV4       0x0010
        !           473: #define UMBRELLA_IPV6       0x0020
        !           474: #define UMBRELLA_DEVICE     0x0040
        !           475: #define UMBRELLA_DEVICESZ   sizeof(daemon->umbrella_device)
        !           476: 
        !           477: struct umbrella_opt {
        !           478:   u8 magic[4];
        !           479:   u8 version;
        !           480:   u8 flags;
        !           481:   /* We have 4 possible fields since we'll never send both IPv4 and
        !           482:    * IPv6, so using the larger of the two to calculate max buffer size.
        !           483:    * Each field also has a type header.  So the following accounts for
        !           484:    * the type headers and each field size to get a max buffer size.
        !           485:    */
        !           486:   u8 fields[4 * UMBRELLA_TYPESZ + UMBRELLA_ORGSZ + IN6ADDRSZ + UMBRELLA_DEVICESZ + UMBRELLA_ASSETSZ];
        !           487: };
        !           488: 
        !           489: static size_t add_umbrella_opt(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source, int *cacheable)
        !           490: {
        !           491:   *cacheable = 0;
        !           492: 
        !           493:   struct umbrella_opt opt = {{"ODNS"}, UMBRELLA_VERSION, 0, {}};
        !           494:   u8 *u = &opt.fields[0];
        !           495:   int family = source->sa.sa_family;
        !           496:   int size = family == AF_INET ? INADDRSZ : IN6ADDRSZ;
        !           497: 
        !           498:   if (daemon->umbrella_org)
        !           499:     {
        !           500:       PUTSHORT(UMBRELLA_ORG, u);
        !           501:       PUTLONG(daemon->umbrella_org, u);
        !           502:     }
        !           503:   
        !           504:   PUTSHORT(family == AF_INET ? UMBRELLA_IPV4 : UMBRELLA_IPV6, u);
        !           505:   memcpy(u, get_addrp(source, family), size);
        !           506:   u += size;
        !           507:   
        !           508:   if (option_bool(OPT_UMBRELLA_DEVID))
        !           509:     {
        !           510:       PUTSHORT(UMBRELLA_DEVICE, u);
        !           511:       memcpy(u, (char *)&daemon->umbrella_device, UMBRELLA_DEVICESZ);
        !           512:       u += UMBRELLA_DEVICESZ;
        !           513:     }
        !           514: 
        !           515:   if (daemon->umbrella_asset)
        !           516:     {
        !           517:       PUTSHORT(UMBRELLA_ASSET, u);
        !           518:       PUTLONG(daemon->umbrella_asset, u);
        !           519:     }
        !           520:   
        !           521:   return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_UMBRELLA, (unsigned char *)&opt, u - (u8 *)&opt, 0, 1);
        !           522: }
        !           523: 
1.1.1.2   misho     524: /* Set *check_subnet if we add a client subnet option, which needs to checked 
                    525:    in the reply. Set *cacheable to zero if we add an option which the answer
                    526:    may depend on. */
1.1       misho     527: size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit, 
1.1.1.3 ! misho     528:                        union mysockaddr *source, time_t now, int *cacheable)    
1.1       misho     529: {
1.1.1.2   misho     530:   *cacheable = 1;
                    531:   
1.1.1.3 ! misho     532:   plen  = add_mac(header, plen, limit, source, now, cacheable);
        !           533:   plen = add_dns_client(header, plen, limit, source, now, cacheable);
1.1.1.2   misho     534:   
1.1       misho     535:   if (daemon->dns_client_id)
                    536:     plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID, 
                    537:                            (unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0, 1);
1.1.1.3 ! misho     538: 
        !           539:   if (option_bool(OPT_UMBRELLA))
        !           540:     plen = add_umbrella_opt(header, plen, limit, source, cacheable);
1.1       misho     541:   
1.1.1.3 ! misho     542:   plen = add_source_addr(header, plen, limit, source, cacheable);
        !           543:          
1.1       misho     544:   return plen;
                    545: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>