2 * lib/krb5/os/localaddr.c
4 * Copyright 1990,1991 by the Massachusetts Institute of Technology.
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. M.I.T. makes no representations about the suitability of
20 * this software for any purpose. It is provided "as is" without express
21 * or implied warranty.
24 * Return the protocol addresses supported by this host.
26 * XNS support is untested, but "Should just work".
32 #if !defined(HAVE_MACSOCK_H) && !defined(_MSDOS) && !defined(_WIN32)
34 /* needed for solaris, harmless elsewhere... */
36 #include <sys/ioctl.h>
41 * The SIOCGIF* ioctls require a socket.
42 * It doesn't matter *what* kind of socket they use, but it has to be
45 * Of course, you can't just ask the kernel for a socket of arbitrary
46 * type; you have to ask for one with a valid type.
49 #ifdef HAVE_NETINET_IN_H
51 #include <netinet/in.h>
54 #define USE_AF AF_INET
55 #define USE_TYPE SOCK_DGRAM
67 #define USE_TYPE SOCK_DGRAM
68 #define USE_PROTO 0 /* guess */
73 * Add more address families here.
77 * BSD 4.4 defines the size of an ifreq to be
78 * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
79 * However, under earlier systems, sa_len isn't present, so the size is
80 * just sizeof(struct ifreq)
84 #define max(a,b) ((a) > (b) ? (a) : (b))
86 #define ifreq_size(i) max(sizeof(struct ifreq),\
87 sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
89 #define ifreq_size(i) sizeof(struct ifreq)
90 #endif /* HAVE_SA_LEN*/
97 * Return all the protocol addresses of this host.
99 * We could kludge up something to return all addresses, assuming that
100 * they're valid kerberos protocol addresses, but we wouldn't know the
101 * real size of the sockaddr or know which part of it was actually the
104 * This uses the SIOCGIFCONF, SIOCGIFFLAGS, and SIOCGIFADDR ioctl's.
107 KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
108 krb5_os_localaddr(context, addr)
109 krb5_context context;
110 krb5_address FAR * FAR * FAR *addr;
112 struct ifreq *ifr, ifreq;
116 krb5_address *addr_temp [ 1024/sizeof(struct ifreq) ];
120 memset(buf, 0, sizeof(buf));
121 ifc.ifc_len = sizeof(buf);
124 s = socket (USE_AF, USE_TYPE, USE_PROTO);
128 code = ioctl (s, SIOCGIFCONF, (char *)&ifc);
137 for (i = 0; i < n; i+= ifreq_size(*ifr) ) {
138 krb5_address *address;
139 ifr = (struct ifreq *)((caddr_t) ifc.ifc_buf+i);
141 strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof (ifreq.ifr_name));
142 if (ioctl (s, SIOCGIFFLAGS, (char *)&ifreq) < 0)
146 if (ifreq.ifr_flags & IFF_LOOPBACK)
150 if (!(ifreq.ifr_flags & IFF_UP))
151 /* interface is down; skip */
154 /* ifr->ifr_addr has what we want! */
155 switch (ifr->ifr_addr.sa_family) {
156 #ifdef HAVE_NETINET_IN_H
159 struct sockaddr_in *in =
160 (struct sockaddr_in *)&ifr->ifr_addr;
162 address = (krb5_address *)
163 malloc (sizeof(krb5_address));
165 address->magic = KV5M_ADDRESS;
166 address->addrtype = ADDRTYPE_INET;
167 address->length = sizeof(struct in_addr);
168 address->contents = (unsigned char *)malloc(address->length);
169 if (!address->contents) {
174 memcpy ((char *)address->contents,
175 (char *)&in->sin_addr,
185 struct sockaddr_ns *ns =
186 (struct sockaddr_ns *)&ifr->ifr_addr;
187 address = (krb5_address *)
188 malloc (sizeof (krb5_address) + sizeof (struct ns_addr));
190 address->magic = KV5M_ADDRESS;
191 address->addrtype = ADDRTYPE_XNS;
193 /* XXX should we perhaps use ns_host instead? */
195 address->length = sizeof(struct ns_addr);
196 address->contents = (unsigned char *)malloc(address->length);
197 if (!address->contents) {
202 memcpy ((char *)address->contents,
203 (char *)&ns->sns_addr,
212 * Add more address families here..
218 addr_temp[n_found++] = address;
223 *addr = (krb5_address **)malloc (sizeof (krb5_address *) * (n_found+1));
228 for (i=0; i<n_found; i++) {
229 krb5_xfree(addr_temp[i]);
235 for (i=0; i<n_found; i++) {
236 (*addr)[i] = addr_temp[i];
238 (*addr)[n_found] = 0;
242 #else /* Windows/Mac version */
245 * Hold on to your lunch! Backup kludge method of obtaining your
246 * local IP address, courtesy of Windows Socket Network Programming,
249 #if defined(_MSDOS) || defined(_WIN32)
250 static struct hostent *local_addr_fallback_kludge()
252 static struct hostent host;
253 static SOCKADDR_IN addr;
254 static char * ip_ptrs[2];
256 int size = sizeof(SOCKADDR);
259 sock = socket(AF_INET, SOCK_DGRAM, 0);
260 if (sock == INVALID_SOCKET)
263 /* connect to arbitrary port and address (NOT loopback) */
264 addr.sin_family = AF_INET;
265 addr.sin_port = htons(IPPORT_ECHO);
266 addr.sin_addr.s_addr = inet_addr("204.137.220.51");
268 err = connect(sock, (LPSOCKADDR) &addr, sizeof(SOCKADDR));
269 if (err == SOCKET_ERROR)
272 err = getsockname(sock, (LPSOCKADDR) &addr, (int FAR *) size);
273 if (err == SOCKET_ERROR)
280 host.h_addrtype = AF_INET;
282 host.h_addr_list = ip_ptrs;
283 ip_ptrs[0] = (char *) &addr.sin_addr.s_addr;
290 /* No ioctls in winsock so we just assume there is only one networking
291 * card per machine, so gethostent is good enough.
293 KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
294 krb5_os_localaddr (krb5_context context, krb5_address ***addr) {
295 char host[64]; /* Name of local machine */
296 struct hostent *hostrec;
299 *addr = calloc (2, sizeof (krb5_address *));
305 if (gethostname (host, sizeof(host))) {
310 hostrec = gethostbyname (host);
311 if (hostrec == NULL) {
317 hostrec = local_addr_fallback_kludge();
322 (*addr)[0] = calloc (1, sizeof(krb5_address));
323 if ((*addr)[0] == NULL) {
327 (*addr)[0]->magic = KV5M_ADDRESS;
328 (*addr)[0]->addrtype = hostrec->h_addrtype;
329 (*addr)[0]->length = hostrec->h_length;
330 (*addr)[0]->contents = (unsigned char *)malloc((*addr)[0]->length);
331 if (!(*addr)[0]->contents) {
336 memcpy ((*addr)[0]->contents,
340 /* FIXME, deal with the case where gethostent returns multiple addrs */