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.1 2006/02/25 18:23:25 marschap 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 u_int32_t 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
= 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 */