source: rtems/cpukit/libnetworking/libc/res_update.c @ 09fdb5e8

4.104.114.84.95
Last change on this file since 09fdb5e8 was 09fdb5e8, checked in by Ralf Corsepius <ralf.corsepius@…>, on 03/30/07 at 05:15:58

Eliminate SCCS, LINT. Add HAVE_CONFIG_H.

  • Property mode set to 100644
File size: 13.8 KB
Line 
1/*
2 * Copyright (c) 1996 by Internet Software Consortium.
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
9 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
10 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
11 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
13 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
15 * SOFTWARE.
16 */
17
18#if HAVE_CONFIG_H
19#include "config.h"
20#endif
21
22/*
23 * Based on the Dynamic DNS reference implementation by Viraj Bais
24 * <viraj_bais@ccm.fm.intel.com>
25 */
26
27#include <sys/param.h>
28#include <sys/socket.h>
29#include <sys/time.h>
30#include <netinet/in.h>
31#include <arpa/inet.h>
32#include <arpa/nameser.h>
33#include <errno.h>
34#include <limits.h>
35#include <netdb.h>
36#include <resolv.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40
41/*
42 * Separate a linked list of records into groups so that all records
43 * in a group will belong to a single zone on the nameserver.
44 * Create a dynamic update packet for each zone and send it to the
45 * nameservers for that zone, and await answer.
46 * Abort if error occurs in updating any zone.
47 * Return the number of zones updated on success, < 0 on error.
48 *
49 * On error, caller must deal with the unsynchronized zones
50 * eg. an A record might have been successfully added to the forward
51 * zone but the corresponding PTR record would be missing if error
52 * was encountered while updating the reverse zone.
53 */
54
55#define NSMAX 16
56
57struct ns1 {
58        char nsname[MAXDNAME];
59        struct in_addr nsaddr1;
60};
61
62struct zonegrp {
63        char            z_origin[MAXDNAME];
64        int16_t         z_class;
65        char            z_soardata[MAXDNAME + 5 * INT32SZ];
66        struct ns1      z_ns[NSMAX];
67        int             z_nscount;
68        ns_updrec *     z_rr;
69        struct zonegrp *z_next;
70};
71
72
73int
74res_update(ns_updrec *rrecp_in) {
75        ns_updrec *rrecp, *tmprrecp;
76        u_char buf[PACKETSZ], answer[PACKETSZ], packet[2*PACKETSZ];
77        char name[MAXDNAME], zname[MAXDNAME], primary[MAXDNAME],
78             mailaddr[MAXDNAME];
79        u_char soardata[2*MAXCDNAME+5*INT32SZ];
80        char *dname, *svdname, *cp1, *target;
81        u_char *cp, *eom;
82        HEADER *hp = (HEADER *) answer;
83        struct zonegrp *zptr = NULL, *tmpzptr, *prevzptr, *zgrp_start = NULL;
84        int i, j, k = 0, n, ancount, nscount, arcount, rcode, rdatasize,
85            newgroup, done, myzone, seen_before, numzones = 0;
86        u_int16_t dlen, class, qclass, type, qtype;
87        u_int32_t ttl;
88
89        if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
90                h_errno = NETDB_INTERNAL;
91                return (-1);
92        }
93
94        for (rrecp = rrecp_in; rrecp; rrecp = rrecp->r_next) {
95                dname = rrecp->r_dname;
96                n = strlen(dname);
97                if (dname[n-1] == '.')
98                        dname[n-1] = '\0';
99                qtype = T_SOA;
100                qclass = rrecp->r_class;
101                done = 0;
102                seen_before = 0;
103
104                while (!done && dname) {
105                    if (qtype == T_SOA) {
106                        for (tmpzptr = zgrp_start;
107                             tmpzptr && !seen_before;
108                             tmpzptr = tmpzptr->z_next) {
109                                if (strcasecmp(dname,
110                                               tmpzptr->z_origin) == 0 &&
111                                    tmpzptr->z_class == qclass)
112                                        seen_before++;
113                                for (tmprrecp = tmpzptr->z_rr;
114                                     tmprrecp && !seen_before;
115                                     tmprrecp = tmprrecp->r_grpnext)
116                                if (strcasecmp(dname, tmprrecp->r_dname) == 0
117                                    && tmprrecp->r_class == qclass) {
118                                        seen_before++;
119                                        break;
120                                }
121                                if (seen_before) {
122                                        /*
123                                         * Append to the end of
124                                         * current group.
125                                         */
126                                        for (tmprrecp = tmpzptr->z_rr;
127                                             tmprrecp->r_grpnext;
128                                             tmprrecp = tmprrecp->r_grpnext)
129                                                (void)NULL;
130                                        tmprrecp->r_grpnext = rrecp;
131                                        rrecp->r_grpnext = NULL;
132                                        done = 1;
133                                        break;
134                                }
135                        }
136                } else if (qtype == T_A) {
137                    for (tmpzptr = zgrp_start;
138                         tmpzptr && !done;
139                         tmpzptr = tmpzptr->z_next)
140                            for (i = 0; i < tmpzptr->z_nscount; i++)
141                                if (tmpzptr->z_class == qclass &&
142                                    strcasecmp(tmpzptr->z_ns[i].nsname,
143                                               dname) == 0 &&
144                                    tmpzptr->z_ns[i].nsaddr1.s_addr != 0) {
145                                        zptr->z_ns[k].nsaddr1.s_addr =
146                                         tmpzptr->z_ns[i].nsaddr1.s_addr;
147                                        done = 1;
148                                        break;
149                                }
150                }
151                if (done)
152                    break;
153                n = res_mkquery(QUERY, dname, qclass, qtype, NULL,
154                                0, NULL, buf, sizeof buf);
155                if (n <= 0) {
156                    fprintf(stderr, "res_update: mkquery failed\n");
157                    return (n);
158                }
159                n = res_send(buf, n, answer, sizeof answer);
160                if (n < 0) {
161                    fprintf(stderr, "res_update: send error for %s\n",
162                            rrecp->r_dname);
163                    return (n);
164                }
165                if (n < HFIXEDSZ)
166                        return (-1);
167                ancount = ntohs(hp->ancount);
168                nscount = ntohs(hp->nscount);
169                arcount = ntohs(hp->arcount);
170                rcode = hp->rcode;
171                cp = answer + HFIXEDSZ;
172                eom = answer + n;
173                /* skip the question section */
174                n = dn_skipname(cp, eom);
175                if (n < 0 || cp + n + 2 * INT16SZ > eom)
176                        return (-1);
177                cp += n + 2 * INT16SZ;
178
179                if (qtype == T_SOA) {
180                    if (ancount == 0 && nscount == 0 && arcount == 0) {
181                        /*
182                         * if (rcode == NOERROR) then the dname exists but
183                         * has no soa record associated with it.
184                         * if (rcode == NXDOMAIN) then the dname does not
185                         * exist and the server is replying out of NCACHE.
186                         * in either case, proceed with the next try
187                         */
188                        dname = strchr(dname, '.');
189                        if (dname != NULL)
190                                dname++;
191                        continue;
192                    } else if ((rcode == NOERROR || rcode == NXDOMAIN) &&
193                               ancount == 0 &&
194                               nscount == 1 && arcount == 0) {
195                        /*
196                         * name/data does not exist, soa record supplied in the
197                         * authority section
198                         */
199                        /* authority section must contain the soa record */
200                        if ((n = dn_expand(answer, eom, cp, zname,
201                                        sizeof zname)) < 0)
202                            return (n);
203                        cp += n;
204                        if (cp + 2 * INT16SZ > eom)
205                                return (-1);
206                        GETSHORT(type, cp);
207                        GETSHORT(class, cp);
208                        if (type != T_SOA || class != qclass) {
209                            fprintf(stderr, "unknown answer\n");
210                            return (-1);
211                        }
212                        myzone = 0;
213                        svdname = dname;
214                        while (dname)
215                            if (strcasecmp(dname, zname) == 0) {
216                                myzone = 1;
217                                break;
218                            } else if ((dname = strchr(dname, '.')) != NULL)
219                                dname++;
220                        if (!myzone) {
221                            dname = strchr(svdname, '.');
222                            if (dname != NULL)
223                                dname++;
224                            continue;
225                        }
226                        nscount = 0;
227                        /* fallthrough */
228                    } else if (rcode == NOERROR && ancount == 1) {
229                        /*
230                         * found the zone name
231                         * new servers will supply NS records for the zone
232                         * in authority section and A records for those
233                         * nameservers in the additional section
234                         * older servers have to be explicitly queried for
235                         * NS records for the zone
236                         */
237                        /* answer section must contain the soa record */
238                        if ((n = dn_expand(answer, eom, cp, zname,
239                                           sizeof zname)) < 0)
240                                return (n);
241                        else
242                                cp += n;
243                        if (cp + 2 * INT16SZ > eom)
244                                return (-1);
245                        GETSHORT(type, cp);
246                        GETSHORT(class, cp);
247                        if (type == T_CNAME) {
248                                dname = strchr(dname, '.');
249                                if (dname != NULL)
250                                        dname++;
251                                continue;
252                        }
253                        if (strcasecmp(dname, zname) != 0 ||
254                            type != T_SOA ||
255                            class != rrecp->r_class) {
256                                fprintf(stderr, "unknown answer\n");
257                                return (-1);
258                        }
259                        /* FALLTHROUGH */
260                    } else {
261                        fprintf(stderr,
262                "unknown response: ans=%d, auth=%d, add=%d, rcode=%d\n",
263                                ancount, nscount, arcount, hp->rcode);
264                        return (-1);
265                    }
266                    if (cp + INT32SZ + INT16SZ > eom)
267                            return (-1);
268                    /* continue processing the soa record */
269                    GETLONG(ttl, cp);
270                    GETSHORT(dlen, cp);
271                    if (cp + dlen > eom)
272                            return (-1);
273                    newgroup = 1;
274                    zptr = zgrp_start;
275                    prevzptr = NULL;
276                    while (zptr) {
277                        if (strcasecmp(zname, zptr->z_origin) == 0 &&
278                            type == T_SOA && class == qclass) {
279                                newgroup = 0;
280                                break;
281                        }
282                        prevzptr = zptr;
283                        zptr = zptr->z_next;
284                    }
285                    if (!newgroup) {
286                        for (tmprrecp = zptr->z_rr;
287                             tmprrecp->r_grpnext;
288                             tmprrecp = tmprrecp->r_grpnext)
289                                    ;
290                        tmprrecp->r_grpnext = rrecp;
291                        rrecp->r_grpnext = NULL;
292                        done = 1;
293                        cp += dlen;
294                        break;
295                    } else {
296                        if ((n = dn_expand(answer, eom, cp, primary,
297                                           sizeof primary)) < 0)
298                            return (n);
299                        cp += n;
300                        /*
301                         * We don't have to bounds check here because the
302                         * next use of 'cp' is in dn_expand().
303                         */
304                        cp1 = (char *)soardata;
305                        strcpy(cp1, primary);
306                        cp1 += strlen(cp1) + 1;
307                        if ((n = dn_expand(answer, eom, cp, mailaddr,
308                                           sizeof mailaddr)) < 0)
309                            return (n);
310                        cp += n;
311                        strcpy(cp1, mailaddr);
312                        cp1 += strlen(cp1) + 1;
313                        if (cp + 5*INT32SZ > eom)
314                                return (-1);
315                        memcpy(cp1, cp, 5*INT32SZ);
316                        cp += 5*INT32SZ;
317                        cp1 += 5*INT32SZ;
318                        rdatasize = (u_char *)cp1 - soardata;
319                        zptr = calloc(1, sizeof(struct zonegrp));
320                        if (zptr == NULL)
321                            return (-1);
322                        if (zgrp_start == NULL)
323                            zgrp_start = zptr;
324                        else
325                            prevzptr->z_next = zptr;
326                        zptr->z_rr = rrecp;
327                        rrecp->r_grpnext = NULL;
328                        strcpy(zptr->z_origin, zname);
329                        zptr->z_class = class;
330                        memcpy(zptr->z_soardata, soardata, rdatasize);
331                        /* fallthrough to process NS and A records */
332                    }
333                } else if (qtype == T_NS) {
334                    if (rcode == NOERROR && ancount > 0) {
335                        strcpy(zname, dname);
336                        for (zptr = zgrp_start; zptr; zptr = zptr->z_next) {
337                            if (strcasecmp(zname, zptr->z_origin) == 0)
338                                break;
339                        }
340                        if (zptr == NULL)
341                            /* should not happen */
342                            return (-1);
343                        if (nscount > 0) {
344                            /*
345                             * answer and authority sections contain
346                             * the same information, skip answer section
347                             */
348                            for (j = 0; j < ancount; j++) {
349                                n = dn_skipname(cp, eom);
350                                if (n < 0)
351                                        return (-1);
352                                n += 2*INT16SZ + INT32SZ;
353                                if (cp + n + INT16SZ > eom)
354                                        return (-1);
355                                cp += n;
356                                GETSHORT(dlen, cp);
357                                cp += dlen;
358                            }
359                        } else
360                            nscount = ancount;
361                        /* fallthrough to process NS and A records */
362                    } else {
363                        fprintf(stderr, "cannot determine nameservers for %s:\
364ans=%d, auth=%d, add=%d, rcode=%d\n",
365                                dname, ancount, nscount, arcount, hp->rcode);
366                        return (-1);
367                    }
368                } else if (qtype == T_A) {
369                    if (rcode == NOERROR && ancount > 0) {
370                        arcount = ancount;
371                        ancount = nscount = 0;
372                        /* fallthrough to process A records */
373                    } else {
374                        fprintf(stderr, "cannot determine address for %s:\
375ans=%d, auth=%d, add=%d, rcode=%d\n",
376                                dname, ancount, nscount, arcount, hp->rcode);
377                        return (-1);
378                    }
379                }
380                /* process NS records for the zone */
381                j = 0;
382                for (i = 0; i < nscount; i++) {
383                    if ((n = dn_expand(answer, eom, cp, name,
384                                        sizeof name)) < 0)
385                        return (n);
386                    cp += n;
387                    if (cp + 3 * INT16SZ + INT32SZ > eom)
388                            return (-1);
389                    GETSHORT(type, cp);
390                    GETSHORT(class, cp);
391                    GETLONG(ttl, cp);
392                    GETSHORT(dlen, cp);
393                    if (cp + dlen > eom)
394                        return (-1);
395                    if (strcasecmp(name, zname) == 0 &&
396                        type == T_NS && class == qclass) {
397                                if ((n = dn_expand(answer, eom, cp,
398                                                   name, sizeof name)) < 0)
399                                        return (n);
400                            target = zptr->z_ns[j++].nsname;
401                            strcpy(target, name);
402                    }
403                    cp += dlen;
404                }
405                if (zptr->z_nscount == 0)
406                    zptr->z_nscount = j;
407                /* get addresses for the nameservers */
408                for (i = 0; i < arcount; i++) {
409                    if ((n = dn_expand(answer, eom, cp, name,
410                                        sizeof name)) < 0)
411                        return (n);
412                    cp += n;
413                    if (cp + 3 * INT16SZ + INT32SZ > eom)
414                        return (-1);
415                    GETSHORT(type, cp);
416                    GETSHORT(class, cp);
417                    GETLONG(ttl, cp);
418                    GETSHORT(dlen, cp);
419                    if (cp + dlen > eom)
420                            return (-1);
421                    if (type == T_A && dlen == INT32SZ && class == qclass) {
422                        for (j = 0; j < zptr->z_nscount; j++)
423                            if (strcasecmp(name, zptr->z_ns[j].nsname) == 0) {
424                                memcpy(&zptr->z_ns[j].nsaddr1.s_addr, cp,
425                                       INT32SZ);
426                                break;
427                            }
428                    }
429                    cp += dlen;
430                }
431                if (zptr->z_nscount == 0) {
432                    dname = zname;
433                    qtype = T_NS;
434                    continue;
435                }
436                done = 1;
437                for (k = 0; k < zptr->z_nscount; k++)
438                    if (zptr->z_ns[k].nsaddr1.s_addr == 0) {
439                        done = 0;
440                        dname = zptr->z_ns[k].nsname;
441                        qtype = T_A;
442                    }
443
444            } /* while */
445        }
446
447        _res.options |= RES_DEBUG;
448        for (zptr = zgrp_start; zptr; zptr = zptr->z_next) {
449
450                /* append zone section */
451                rrecp = res_mkupdrec(ns_s_zn, zptr->z_origin,
452                                     zptr->z_class, ns_t_soa, 0);
453                if (rrecp == NULL) {
454                        fprintf(stderr, "saverrec error\n");
455                        fflush(stderr);
456                        return (-1);
457                }
458                rrecp->r_grpnext = zptr->z_rr;
459                zptr->z_rr = rrecp;
460
461                n = res_mkupdate(zptr->z_rr, packet, sizeof packet);
462                if (n < 0) {
463                        fprintf(stderr, "res_mkupdate error\n");
464                        fflush(stderr);
465                        return (-1);
466                } else
467                        fprintf(stdout, "res_mkupdate: packet size = %d\n", n);
468
469                /*
470                 * Override the list of NS records from res_init() with
471                 * the authoritative nameservers for the zone being updated.
472                 * Sort primary to be the first in the list of nameservers.
473                 */
474                for (i = 0; i < zptr->z_nscount; i++) {
475                        if (strcasecmp(zptr->z_ns[i].nsname,
476                                       zptr->z_soardata) == 0) {
477                                struct in_addr tmpaddr;
478
479                                if (i != 0) {
480                                        strcpy(zptr->z_ns[i].nsname,
481                                               zptr->z_ns[0].nsname);
482                                        strcpy(zptr->z_ns[0].nsname,
483                                               zptr->z_soardata);
484                                        tmpaddr = zptr->z_ns[i].nsaddr1;
485                                        zptr->z_ns[i].nsaddr1 =
486                                                zptr->z_ns[0].nsaddr1;
487                                        zptr->z_ns[0].nsaddr1 = tmpaddr;
488                                }
489                                break;
490                        }
491                }
492                for (i = 0; i < MAXNS; i++) {
493                        _res.nsaddr_list[i].sin_addr = zptr->z_ns[i].nsaddr1;
494                        _res.nsaddr_list[i].sin_family = AF_INET;
495                        _res.nsaddr_list[i].sin_port = htons(NAMESERVER_PORT);
496                }
497                _res.nscount = (zptr->z_nscount < MAXNS) ?
498                                        zptr->z_nscount : MAXNS;
499                n = res_send(packet, n, answer, sizeof(answer));
500                if (n < 0) {
501                        fprintf(stderr, "res_send: send error, n=%d\n", n);
502                        break;
503                } else
504                        numzones++;
505        }
506
507        /* free malloc'ed memory */
508        while(zgrp_start) {
509                zptr = zgrp_start;
510                zgrp_start = zgrp_start->z_next;
511                res_freeupdrec(zptr->z_rr);  /* Zone section we allocated. */
512                free((char *)zptr);
513        }
514
515        return (numzones);
516}
Note: See TracBrowser for help on using the repository browser.