~ubuntu-branches/ubuntu/warty/net-tools/warty

« back to all changes in this revision

Viewing changes to lib/inet.c

  • Committer: Bazaar Package Importer
  • Author(s): Bernd Eckenfels
  • Date: 2001-11-24 06:26:37 UTC
  • Revision ID: james.westby@ubuntu.com-20011124062637-1y96kzx03e8dbi55
Tags: upstream-1.60
ImportĀ upstreamĀ versionĀ 1.60

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * lib/inet.c This file contains an implementation of the "INET"
 
3
 *              support functions for the net-tools.
 
4
 *              (NET-3 base distribution).
 
5
 *
 
6
 * Version:    $Id: inet.c,v 1.13 1999/12/11 13:35:56 freitag Exp $
 
7
 *
 
8
 * Author:      Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
 
9
 *              Copyright 1993 MicroWalt Corporation
 
10
 *
 
11
 * Modified:
 
12
 *960113 {1.21} Bernd Eckenfels :       rresolve cache bug.
 
13
 *960128 {1.22} Bernd Eckenfels :       endian bug in print
 
14
 *960203 {1.23} Bernd Eckenfels :       net-features support
 
15
 *960217 {1.24} Bernd Eckenfels :       get_sname
 
16
 *960219 {1.25} Bernd Eckenfels :       extern int h_errno
 
17
 *960329 {1.26} Bernd Eckenfels :       resolve 255.255.255.255 
 
18
 *980101 {1.27} Bernd Eckenfels :       resolve raw sockets in /etc/protocols
 
19
 *990302 {1.28} Phil Blundell   :       add netmask to INET_rresolve
 
20
 *991007        Kurt Garloff    :       rresolve, resolve: may be hosts
 
21
 *              <garloff@suse.de>       store type (host?) in cache 
 
22
 *
 
23
 *              This program is free software; you can redistribute it
 
24
 *              and/or  modify it under  the terms of  the GNU General
 
25
 *              Public  License as  published  by  the  Free  Software
 
26
 *              Foundation;  either  version 2 of the License, or  (at
 
27
 *              your option) any later version.
 
28
 */
 
29
#include "config.h"
 
30
 
 
31
/* FIXME.  Split this file into inet4.c for the IPv4 specific parts
 
32
   and inet.c for those shared between IPv4 and IPv6.  */
 
33
 
 
34
#if HAVE_AFINET || HAVE_AFINET6
 
35
#include <netinet/in.h>
 
36
#include <sys/types.h>
 
37
#include <sys/socket.h>
 
38
#include <arpa/inet.h>
 
39
#include <arpa/nameser.h>
 
40
#include <ctype.h>
 
41
#include <errno.h>
 
42
#include <netdb.h>
 
43
#include <resolv.h>
 
44
#include <stdlib.h>
 
45
#include <string.h>
 
46
#include <stdio.h>
 
47
#include <unistd.h>
 
48
#include "version.h"
 
49
#include "net-support.h"
 
50
#include "pathnames.h"
 
51
#include "intl.h"
 
52
#include "util.h"
 
53
 
 
54
extern int h_errno;             /* some netdb.h versions don't export this */
 
55
 
 
56
/* cache */
 
57
struct addr {
 
58
    struct sockaddr_in addr;
 
59
    char *name;
 
60
    int host;
 
61
    struct addr *next;
 
62
};
 
63
 
 
64
struct service {
 
65
    int number;
 
66
    char *name;
 
67
    struct service *next;
 
68
};
 
69
 
 
70
static struct service *tcp_name = NULL, *udp_name = NULL, *raw_name = NULL;
 
71
 
 
72
#if HAVE_AFINET
 
73
 
 
74
static struct addr *INET_nn = NULL;     /* addr-to-name cache           */
 
75
 
 
76
 
 
77
static int INET_resolve(char *name, struct sockaddr_in *sin, int hostfirst)
 
78
{
 
79
    struct hostent *hp;
 
80
    struct netent *np;
 
81
 
 
82
    /* Grmpf. -FvK */
 
83
    sin->sin_family = AF_INET;
 
84
    sin->sin_port = 0;
 
85
 
 
86
    /* Default is special, meaning 0.0.0.0. */
 
87
    if (!strcmp(name, "default")) {
 
88
        sin->sin_addr.s_addr = INADDR_ANY;
 
89
        return (1);
 
90
    }
 
91
    /* Look to see if it's a dotted quad. */
 
92
    if (inet_aton(name, &sin->sin_addr)) {
 
93
        return 0;
 
94
    }
 
95
    /* If we expect this to be a hostname, try hostname database first */
 
96
#ifdef DEBUG
 
97
    if (hostfirst) fprintf (stderr, "gethostbyname (%s)\n", name);
 
98
#endif
 
99
    if (hostfirst && 
 
100
        (hp = gethostbyname(name)) != (struct hostent *) NULL) {
 
101
        memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[0], 
 
102
                sizeof(struct in_addr));
 
103
        return 0;
 
104
    }
 
105
    /* Try the NETWORKS database to see if this is a known network. */
 
106
#ifdef DEBUG
 
107
    fprintf (stderr, "getnetbyname (%s)\n", name);
 
108
#endif
 
109
    if ((np = getnetbyname(name)) != (struct netent *) NULL) {
 
110
        sin->sin_addr.s_addr = htonl(np->n_net);
 
111
        return 1;
 
112
    }
 
113
    if (hostfirst) {
 
114
        /* Don't try again */
 
115
        errno = h_errno;
 
116
        return -1;
 
117
    }
 
118
#ifdef DEBUG
 
119
    res_init();
 
120
    _res.options |= RES_DEBUG;
 
121
#endif
 
122
 
 
123
#ifdef DEBUG
 
124
    fprintf (stderr, "gethostbyname (%s)\n", name);
 
125
#endif
 
126
    if ((hp = gethostbyname(name)) == (struct hostent *) NULL) {
 
127
        errno = h_errno;
 
128
        return -1;
 
129
    }
 
130
    memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[0], 
 
131
           sizeof(struct in_addr));
 
132
 
 
133
    return 0;
 
134
}
 
135
 
 
136
 
 
137
/* numeric: & 0x8000: default instead of *, 
 
138
 *          & 0x4000: host instead of net, 
 
139
 *          & 0x0fff: don't resolve
 
140
 */
 
141
static int INET_rresolve(char *name, size_t len, struct sockaddr_in *sin, 
 
142
                         int numeric, unsigned int netmask)
 
143
{
 
144
    struct hostent *ent;
 
145
    struct netent *np;
 
146
    struct addr *pn;
 
147
    unsigned long ad, host_ad;
 
148
    int host = 0;
 
149
 
 
150
    /* Grmpf. -FvK */
 
151
    if (sin->sin_family != AF_INET) {
 
152
#ifdef DEBUG
 
153
        fprintf(stderr, _("rresolve: unsupport address family %d !\n"), sin->sin_family);
 
154
#endif
 
155
        errno = EAFNOSUPPORT;
 
156
        return (-1);
 
157
    }
 
158
    ad = (unsigned long) sin->sin_addr.s_addr;
 
159
#ifdef DEBUG
 
160
    fprintf (stderr, "rresolve: %08lx, mask %08x, num %08x \n", ad, netmask, numeric);
 
161
#endif
 
162
    if (ad == INADDR_ANY) {
 
163
        if ((numeric & 0x0FFF) == 0) {
 
164
            if (numeric & 0x8000)
 
165
                safe_strncpy(name, "default", len);
 
166
            else
 
167
                safe_strncpy(name, "*", len);
 
168
            return (0);
 
169
        }
 
170
    }
 
171
    if (numeric & 0x0FFF) {
 
172
        safe_strncpy(name, inet_ntoa(sin->sin_addr), len);
 
173
        return (0);
 
174
    }
 
175
 
 
176
    if ((ad & (~netmask)) != 0 || (numeric & 0x4000))
 
177
        host = 1;
 
178
#if 0
 
179
    INET_nn = NULL;
 
180
#endif
 
181
    pn = INET_nn;
 
182
    while (pn != NULL) {
 
183
        if (pn->addr.sin_addr.s_addr == ad && pn->host == host) {
 
184
            safe_strncpy(name, pn->name, len);
 
185
#ifdef DEBUG
 
186
            fprintf (stderr, "rresolve: found %s %08lx in cache\n", (host? "host": "net"), ad);
 
187
#endif
 
188
            return (0);
 
189
        }
 
190
        pn = pn->next;
 
191
    }
 
192
 
 
193
    host_ad = ntohl(ad);
 
194
    np = NULL;
 
195
    ent = NULL;
 
196
    if (host) {
 
197
#ifdef DEBUG
 
198
        fprintf (stderr, "gethostbyaddr (%08lx)\n", ad);
 
199
#endif
 
200
        ent = gethostbyaddr((char *) &ad, 4, AF_INET);
 
201
        if (ent != NULL)
 
202
            safe_strncpy(name, ent->h_name, len);
 
203
    } else {
 
204
#ifdef DEBUG
 
205
        fprintf (stderr, "getnetbyaddr (%08lx)\n", host_ad);
 
206
#endif
 
207
        np = getnetbyaddr(host_ad, AF_INET);
 
208
        if (np != NULL)
 
209
            safe_strncpy(name, np->n_name, len);
 
210
    }
 
211
    if ((ent == NULL) && (np == NULL))
 
212
        safe_strncpy(name, inet_ntoa(sin->sin_addr), len);
 
213
    pn = (struct addr *) malloc(sizeof(struct addr));
 
214
    pn->addr = *sin;
 
215
    pn->next = INET_nn;
 
216
    pn->host = host;
 
217
    pn->name = (char *) malloc(strlen(name) + 1);
 
218
    strcpy(pn->name, name);
 
219
    INET_nn = pn;
 
220
 
 
221
    return (0);
 
222
}
 
223
 
 
224
 
 
225
static void INET_reserror(char *text)
 
226
{
 
227
    herror(text);
 
228
}
 
229
 
 
230
 
 
231
/* Display an Internet socket address. */
 
232
static char *INET_print(unsigned char *ptr)
 
233
{
 
234
    return (inet_ntoa((*(struct in_addr *) ptr)));
 
235
}
 
236
 
 
237
 
 
238
/* Display an Internet socket address. */
 
239
static char *INET_sprint(struct sockaddr *sap, int numeric)
 
240
{
 
241
    static char buff[128];
 
242
 
 
243
    if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
 
244
        return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
 
245
 
 
246
    if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap, 
 
247
                      numeric, 0xffffff00) != 0)
 
248
        return (NULL);
 
249
 
 
250
    return (buff);
 
251
}
 
252
 
 
253
char *INET_sprintmask(struct sockaddr *sap, int numeric, 
 
254
                      unsigned int netmask)
 
255
{
 
256
    static char buff[128];
 
257
 
 
258
    if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
 
259
        return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
 
260
    if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap, 
 
261
                      numeric, netmask) != 0)
 
262
        return (NULL);
 
263
    return (buff);
 
264
}
 
265
 
 
266
 
 
267
static int INET_getsock(char *bufp, struct sockaddr *sap)
 
268
{
 
269
    char *sp = bufp, *bp;
 
270
    unsigned int i;
 
271
    unsigned val;
 
272
    struct sockaddr_in *sin;
 
273
 
 
274
    sin = (struct sockaddr_in *) sap;
 
275
    sin->sin_family = AF_INET;
 
276
    sin->sin_port = 0;
 
277
 
 
278
    val = 0;
 
279
    bp = (char *) &val;
 
280
    for (i = 0; i < sizeof(sin->sin_addr.s_addr); i++) {
 
281
        *sp = toupper(*sp);
 
282
 
 
283
        if ((*sp >= 'A') && (*sp <= 'F'))
 
284
            bp[i] |= (int) (*sp - 'A') + 10;
 
285
        else if ((*sp >= '0') && (*sp <= '9'))
 
286
            bp[i] |= (int) (*sp - '0');
 
287
        else
 
288
            return (-1);
 
289
 
 
290
        bp[i] <<= 4;
 
291
        sp++;
 
292
        *sp = toupper(*sp);
 
293
 
 
294
        if ((*sp >= 'A') && (*sp <= 'F'))
 
295
            bp[i] |= (int) (*sp - 'A') + 10;
 
296
        else if ((*sp >= '0') && (*sp <= '9'))
 
297
            bp[i] |= (int) (*sp - '0');
 
298
        else
 
299
            return (-1);
 
300
 
 
301
        sp++;
 
302
    }
 
303
    sin->sin_addr.s_addr = htonl(val);
 
304
 
 
305
    return (sp - bufp);
 
306
}
 
307
 
 
308
static int INET_input(int type, char *bufp, struct sockaddr *sap)
 
309
{
 
310
    switch (type) {
 
311
    case 1:
 
312
        return (INET_getsock(bufp, sap));
 
313
    case 256:
 
314
        return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1));
 
315
    default:
 
316
        return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0));
 
317
    }
 
318
}
 
319
 
 
320
static int INET_getnetmask(char *adr, struct sockaddr *m, char *name)
 
321
{
 
322
    struct sockaddr_in *mask = (struct sockaddr_in *) m;
 
323
    char *slash, *end;
 
324
    int prefix;
 
325
 
 
326
    if ((slash = strchr(adr, '/')) == NULL)
 
327
        return 0;
 
328
 
 
329
    *slash++ = '\0';
 
330
    prefix = strtoul(slash, &end, 0);
 
331
    if (*end != '\0')
 
332
        return -1;
 
333
 
 
334
    if (name) {
 
335
        sprintf(name, "/%d", prefix);
 
336
    }
 
337
    mask->sin_family = AF_INET;
 
338
    mask->sin_addr.s_addr = htonl(~(0xffffffffU >> prefix));
 
339
    return 1;
 
340
}
 
341
 
 
342
 
 
343
struct aftype inet_aftype =
 
344
{
 
345
    "inet", NULL, /*"DARPA Internet", */ AF_INET, sizeof(unsigned long),
 
346
    INET_print, INET_sprint, INET_input, INET_reserror,
 
347
    NULL /*INET_rprint */ , NULL /*INET_rinput */ ,
 
348
    INET_getnetmask,
 
349
    -1,
 
350
    NULL
 
351
};
 
352
 
 
353
#endif                          /* HAVE_AFINET */
 
354
 
 
355
static void add2list(struct service **namebase, struct service *item)
 
356
{
 
357
    if (*namebase == NULL) {
 
358
        *namebase = item;
 
359
        item->next = NULL;
 
360
    } else {
 
361
        item->next = *namebase;
 
362
        *namebase = item;
 
363
    }
 
364
}
 
365
 
 
366
 
 
367
static struct service *searchlist(struct service *servicebase, int number)
 
368
{
 
369
    struct service *item;
 
370
 
 
371
    for (item = servicebase; item != NULL; item = item->next) {
 
372
        if (item->number == number)
 
373
            return (item);
 
374
    }
 
375
    return (NULL);
 
376
}
 
377
 
 
378
 
 
379
static int read_services(void)
 
380
{
 
381
    struct servent *se;
 
382
    struct protoent *pe;
 
383
    struct service *item;
 
384
 
 
385
    setservent(1);
 
386
    while ((se = getservent())) {
 
387
        /* Allocate a service entry. */
 
388
        item = (struct service *) malloc(sizeof(struct service));
 
389
        if (item == NULL)
 
390
            perror("netstat");
 
391
        item->name = strdup(se->s_name);
 
392
        item->number = se->s_port;
 
393
 
 
394
        /* Fill it in. */
 
395
        if (!strcmp(se->s_proto, "tcp")) {
 
396
            add2list(&tcp_name, item);
 
397
        } else if (!strcmp(se->s_proto, "udp")) {
 
398
            add2list(&udp_name, item);
 
399
        } else if (!strcmp(se->s_proto, "raw")) {
 
400
            add2list(&raw_name, item);
 
401
        }
 
402
    }
 
403
    endservent();
 
404
    setprotoent(1);
 
405
    while ((pe = getprotoent())) {
 
406
        /* Allocate a service entry. */
 
407
        item = (struct service *) malloc(sizeof(struct service));
 
408
        if (item == NULL)
 
409
            perror("netstat");
 
410
        item->name = strdup(pe->p_name);
 
411
        item->number = htons(pe->p_proto);
 
412
        add2list(&raw_name, item);
 
413
    }
 
414
    endprotoent();
 
415
    return (0);
 
416
}
 
417
 
 
418
 
 
419
char *get_sname(int socknumber, char *proto, int numeric)
 
420
{
 
421
    static char buffer[64], init = 0;
 
422
    struct service *item;
 
423
 
 
424
    if (socknumber == 0)
 
425
        return ("*");
 
426
    if (numeric) {
 
427
        sprintf(buffer, "%d", ntohs(socknumber));
 
428
        return (buffer);
 
429
    }
 
430
    if (!init) {
 
431
        (void) read_services();
 
432
        init = 1;
 
433
    }
 
434
    buffer[0] = '\0';
 
435
    if (!strcmp(proto, "tcp")) {
 
436
        if ((item = searchlist(tcp_name, socknumber)) != NULL)
 
437
            sprintf(buffer, "%s", item->name);
 
438
    } else if (!strcmp(proto, "udp")) {
 
439
        if ((item = searchlist(udp_name, socknumber)) != NULL)
 
440
            sprintf(buffer, "%s", item->name);
 
441
    } else if (!strcmp(proto, "raw")) {
 
442
        if ((item = searchlist(raw_name, socknumber)) != NULL)
 
443
            sprintf(buffer, "%s", item->name);
 
444
 
 
445
    }
 
446
    if (!buffer[0])
 
447
        sprintf(buffer, "%d", ntohs(socknumber));
 
448
    return (buffer);
 
449
}
 
450
 
 
451
#endif                          /* HAVE_AFINET || HAVE_AFINET6 */