2
* lib/inet.c This file contains an implementation of the "INET"
3
* support functions for the net-tools.
4
* (NET-3 base distribution).
6
* Version: $Id: inet.c,v 1.13 1999/12/11 13:35:56 freitag Exp $
8
* Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
9
* Copyright 1993 MicroWalt Corporation
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
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.
31
/* FIXME. Split this file into inet4.c for the IPv4 specific parts
32
and inet.c for those shared between IPv4 and IPv6. */
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>
49
#include "net-support.h"
50
#include "pathnames.h"
54
extern int h_errno; /* some netdb.h versions don't export this */
58
struct sockaddr_in addr;
70
static struct service *tcp_name = NULL, *udp_name = NULL, *raw_name = NULL;
74
static struct addr *INET_nn = NULL; /* addr-to-name cache */
77
static int INET_resolve(char *name, struct sockaddr_in *sin, int hostfirst)
83
sin->sin_family = AF_INET;
86
/* Default is special, meaning 0.0.0.0. */
87
if (!strcmp(name, "default")) {
88
sin->sin_addr.s_addr = INADDR_ANY;
91
/* Look to see if it's a dotted quad. */
92
if (inet_aton(name, &sin->sin_addr)) {
95
/* If we expect this to be a hostname, try hostname database first */
97
if (hostfirst) fprintf (stderr, "gethostbyname (%s)\n", name);
100
(hp = gethostbyname(name)) != (struct hostent *) NULL) {
101
memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[0],
102
sizeof(struct in_addr));
105
/* Try the NETWORKS database to see if this is a known network. */
107
fprintf (stderr, "getnetbyname (%s)\n", name);
109
if ((np = getnetbyname(name)) != (struct netent *) NULL) {
110
sin->sin_addr.s_addr = htonl(np->n_net);
114
/* Don't try again */
120
_res.options |= RES_DEBUG;
124
fprintf (stderr, "gethostbyname (%s)\n", name);
126
if ((hp = gethostbyname(name)) == (struct hostent *) NULL) {
130
memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[0],
131
sizeof(struct in_addr));
137
/* numeric: & 0x8000: default instead of *,
138
* & 0x4000: host instead of net,
139
* & 0x0fff: don't resolve
141
static int INET_rresolve(char *name, size_t len, struct sockaddr_in *sin,
142
int numeric, unsigned int netmask)
147
unsigned long ad, host_ad;
151
if (sin->sin_family != AF_INET) {
153
fprintf(stderr, _("rresolve: unsupport address family %d !\n"), sin->sin_family);
155
errno = EAFNOSUPPORT;
158
ad = (unsigned long) sin->sin_addr.s_addr;
160
fprintf (stderr, "rresolve: %08lx, mask %08x, num %08x \n", ad, netmask, numeric);
162
if (ad == INADDR_ANY) {
163
if ((numeric & 0x0FFF) == 0) {
164
if (numeric & 0x8000)
165
safe_strncpy(name, "default", len);
167
safe_strncpy(name, "*", len);
171
if (numeric & 0x0FFF) {
172
safe_strncpy(name, inet_ntoa(sin->sin_addr), len);
176
if ((ad & (~netmask)) != 0 || (numeric & 0x4000))
183
if (pn->addr.sin_addr.s_addr == ad && pn->host == host) {
184
safe_strncpy(name, pn->name, len);
186
fprintf (stderr, "rresolve: found %s %08lx in cache\n", (host? "host": "net"), ad);
198
fprintf (stderr, "gethostbyaddr (%08lx)\n", ad);
200
ent = gethostbyaddr((char *) &ad, 4, AF_INET);
202
safe_strncpy(name, ent->h_name, len);
205
fprintf (stderr, "getnetbyaddr (%08lx)\n", host_ad);
207
np = getnetbyaddr(host_ad, AF_INET);
209
safe_strncpy(name, np->n_name, len);
211
if ((ent == NULL) && (np == NULL))
212
safe_strncpy(name, inet_ntoa(sin->sin_addr), len);
213
pn = (struct addr *) malloc(sizeof(struct addr));
217
pn->name = (char *) malloc(strlen(name) + 1);
218
strcpy(pn->name, name);
225
static void INET_reserror(char *text)
231
/* Display an Internet socket address. */
232
static char *INET_print(unsigned char *ptr)
234
return (inet_ntoa((*(struct in_addr *) ptr)));
238
/* Display an Internet socket address. */
239
static char *INET_sprint(struct sockaddr *sap, int numeric)
241
static char buff[128];
243
if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
244
return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
246
if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap,
247
numeric, 0xffffff00) != 0)
253
char *INET_sprintmask(struct sockaddr *sap, int numeric,
254
unsigned int netmask)
256
static char buff[128];
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)
267
static int INET_getsock(char *bufp, struct sockaddr *sap)
269
char *sp = bufp, *bp;
272
struct sockaddr_in *sin;
274
sin = (struct sockaddr_in *) sap;
275
sin->sin_family = AF_INET;
280
for (i = 0; i < sizeof(sin->sin_addr.s_addr); i++) {
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');
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');
303
sin->sin_addr.s_addr = htonl(val);
308
static int INET_input(int type, char *bufp, struct sockaddr *sap)
312
return (INET_getsock(bufp, sap));
314
return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1));
316
return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0));
320
static int INET_getnetmask(char *adr, struct sockaddr *m, char *name)
322
struct sockaddr_in *mask = (struct sockaddr_in *) m;
326
if ((slash = strchr(adr, '/')) == NULL)
330
prefix = strtoul(slash, &end, 0);
335
sprintf(name, "/%d", prefix);
337
mask->sin_family = AF_INET;
338
mask->sin_addr.s_addr = htonl(~(0xffffffffU >> prefix));
343
struct aftype inet_aftype =
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 */ ,
353
#endif /* HAVE_AFINET */
355
static void add2list(struct service **namebase, struct service *item)
357
if (*namebase == NULL) {
361
item->next = *namebase;
367
static struct service *searchlist(struct service *servicebase, int number)
369
struct service *item;
371
for (item = servicebase; item != NULL; item = item->next) {
372
if (item->number == number)
379
static int read_services(void)
383
struct service *item;
386
while ((se = getservent())) {
387
/* Allocate a service entry. */
388
item = (struct service *) malloc(sizeof(struct service));
391
item->name = strdup(se->s_name);
392
item->number = se->s_port;
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);
405
while ((pe = getprotoent())) {
406
/* Allocate a service entry. */
407
item = (struct service *) malloc(sizeof(struct service));
410
item->name = strdup(pe->p_name);
411
item->number = htons(pe->p_proto);
412
add2list(&raw_name, item);
419
char *get_sname(int socknumber, char *proto, int numeric)
421
static char buffer[64], init = 0;
422
struct service *item;
427
sprintf(buffer, "%d", ntohs(socknumber));
431
(void) read_services();
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);
447
sprintf(buffer, "%d", ntohs(socknumber));
451
#endif /* HAVE_AFINET || HAVE_AFINET6 */