1 /*****************************************************************************
2 * netutils.c: various network functions
3 *****************************************************************************
4 * Copyright (C) 1999, 2000 VideoLAN
6 * Authors: Vincent Seguin <seguin@via.ecp.fr>
7 * Benoit Steiner <benny@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
29 #include <netdb.h> /* gethostbyname() */
30 #include <stdlib.h> /* free(), realloc(), atoi() */
31 #include <errno.h> /* errno() */
32 #include <string.h> /* bzero(), bcopy() */
34 #include <netinet/in.h> /* BSD: struct in_addr */
35 #include <sys/socket.h> /* BSD: struct sockaddr */
36 #ifdef HAVE_ARPA_INET_H
37 #include <arpa/inet.h> /* inet_ntoa(), inet_aton() */
40 #if defined (HAVE_SYS_IOCTL_H)
41 #include <sys/ioctl.h> /* ioctl() */
44 #include <unistd.h> /* needed for ioctl on Solaris */
45 //#include <stropts.h>
47 #if defined (HAVE_NET_IF_H)
48 #include <net/if.h> /* interface (arch-dependent) */
50 #ifdef HAVE_SYS_SOCKIO_H
51 #include <sys/sockio.h>
63 /*****************************************************************************
64 * BuildInetAddr: build an Internet address descriptor
65 *****************************************************************************
66 * Build an internet socket descriptor from a host name, or an ip, and a port.
67 * If the address is NULL, then INADDR_ANY will be used, allowing to receive
68 * on any address for a local socket. Usually, in this case, 'port' is also null
69 * and the function always succeeds.
70 *****************************************************************************/
71 int BuildInetAddr( struct sockaddr_in *p_sa_in, char *psz_in_addr, int i_port )
73 struct hostent *p_hostent; /* host descriptor */
75 memset( p_sa_in, 0, sizeof( struct sockaddr_in ) );
76 p_sa_in->sin_family = AF_INET; /* family */
77 p_sa_in->sin_port = htons( i_port ); /* port */
79 /* Use INADDR_ANY if psz_in_addr is NULL */
80 if( psz_in_addr == NULL )
82 p_sa_in->sin_addr.s_addr = htonl(INADDR_ANY);
84 /* Try to convert address directly from in_addr - this will work if
85 * psz_in_addr is dotted decimal. */
86 #if defined HAVE_ARPA_INET_H && !defined SYS_SOLARIS2_6
87 else if( !inet_aton( psz_in_addr, &p_sa_in->sin_addr) )
89 else if( (p_sa_in->sin_addr.s_addr = inet_addr( psz_in_addr )) == -1 )
92 /* The convertion failed: the address is an host name, which needs
94 intf_DbgMsg("debug: resolving internet address %s...", psz_in_addr);
95 if ( (p_hostent = gethostbyname(psz_in_addr)) == NULL)
97 intf_ErrMsg( "net error: unknown host %s", psz_in_addr );
101 /* Copy the first address of the host in the socket address */
102 memmove( &p_sa_in->sin_addr, p_hostent->h_addr_list[0], p_hostent->h_length );
108 /*****************************************************************************
109 * ServerPort: extract port from a "server:port" adress
110 *****************************************************************************
111 * Returns the port number in a "server:port" address and replace the ":" by
112 * a NUL character, or returns -1.
113 *****************************************************************************/
114 int ServerPort( char *psz_addr )
118 /* Scan string for ':' */
119 for( psz_index = psz_addr; *psz_index && (*psz_index != ':'); psz_index++ )
124 /* If a port number has been found, convert it and return it */
125 if( *psz_index == ':' )
128 return( atoi( psz_index + 1 ) );
135 /*****************************************************************************
136 * ReadIfConf: Read the configuration of an interface
137 *****************************************************************************
138 * i_sockfd must reference a socket open as follow: AF_INET, DOCK_DGRAM, 0
139 *****************************************************************************/
141 /* pbm : SIOCGIFHWADDR, doesn't exist on BSD -> find a portable way to
143 int ReadIfConf(int i_sockfd, if_descr_t* p_ifdescr, char* psz_name)
146 #if defined (HAVE_SYS_IOCTL_H) && defined(HAVE_NET_IF_H)
147 struct ifreq ifr_config;
152 /* Which interface are we interested in ? */
153 strcpy(ifr_config.ifr_name, psz_name);
155 /* Read the flags for that interface */
156 i_rc = ioctl(i_sockfd, SIOCGIFFLAGS, (byte_t *)&ifr_config);
159 p_ifdescr->i_flags = ifr_config.ifr_flags;
160 intf_DbgMsg("%s flags: 0x%x", psz_name, p_ifdescr->i_flags);
164 intf_ErrMsg( "net error: cannot read flags for interface %s (%s)",
165 psz_name, strerror(errno) );
169 /* Read physical address of the interface and store it in our description */
171 i_rc = ioctl(i_sockfd, SIOCGENADDR, (byte_t *)&ifr_config);
173 i_rc = ioctl(i_sockfd, SIOCGIFHWADDR, (byte_t *)&ifr_config);
177 memcpy(&p_ifdescr->sa_phys_addr, &ifr_config.ifr_addr, sizeof(struct sockaddr));
178 intf_DbgMsg("%s MAC address: %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", psz_name,
179 p_ifdescr->sa_phys_addr.sa_data[0]&0xff,
180 p_ifdescr->sa_phys_addr.sa_data[1]&0xff,
181 p_ifdescr->sa_phys_addr.sa_data[2]&0xff,
182 p_ifdescr->sa_phys_addr.sa_data[3]&0xff,
183 p_ifdescr->sa_phys_addr.sa_data[4]&0xff,
184 p_ifdescr->sa_phys_addr.sa_data[5]&0xff);
188 intf_ErrMsg( "net error: cannot read hardware address for %s (%s)",
189 psz_name, strerror(errno) );
193 /* Read IP address of the interface and store it in our description */
194 i_rc = ioctl(i_sockfd, SIOCGIFADDR, (byte_t *)&ifr_config);
197 memcpy(&p_ifdescr->sa_net_addr, &ifr_config.ifr_addr, sizeof(struct sockaddr));
198 intf_DbgMsg("%s IP address: %s", psz_name,
199 inet_ntoa(p_ifdescr->sa_net_addr.sin_addr));
203 intf_ErrMsg( "net error: cannot read network address for %s (%s)",
204 psz_name, strerror(errno) );
208 /* Read broadcast address of the interface and store it in our description */
209 if(p_ifdescr->i_flags & IFF_POINTOPOINT)
211 intf_DbgMsg("%s doen't not support broadcast", psz_name);
212 i_rc = ioctl(i_sockfd, SIOCGIFDSTADDR, (byte_t *)&ifr_config);
216 intf_DbgMsg("%s supports broadcast", psz_name);
217 i_rc = ioctl(i_sockfd, SIOCGIFBRDADDR, (byte_t *)&ifr_config);
221 memcpy(&p_ifdescr->sa_bcast_addr, &ifr_config.ifr_addr, sizeof(struct sockaddr));
222 intf_DbgMsg("%s broadcast address: %s", psz_name,
223 inet_ntoa(p_ifdescr->sa_bcast_addr.sin_addr));
227 intf_ErrMsg( "net error: cannot read broadcast address for %s (%s)",
228 psz_name, strerror(errno));
237 /*****************************************************************************
238 * ReadNetConf: Retrieve the network configuration of the host
239 *****************************************************************************
240 * Only IP interfaces are listed, and only if they are up
241 * i_sockfd must reference a socket open as follow: AF_INET, DOCK_DGRAM, 0
242 *****************************************************************************/
243 int ReadNetConf(int i_sockfd, net_descr_t* p_net_descr)
247 #if defined (HAVE_SYS_IOCTL_H) && defined (HAVE_NET_IF_H)
248 struct ifreq* a_ifr_ifconf = NULL;
249 struct ifreq* p_ifr_current_if;
250 struct ifconf ifc_netconf;
257 /* Start by assuming we have few than 3 interfaces (i_if_number will
258 be incremented by 1 when entering the loop) */
261 /* Retrieve network configuration for that host */
265 a_ifr_ifconf = realloc(a_ifr_ifconf, i_if_number*sizeof(struct ifreq));
266 ifc_netconf.ifc_len = i_if_number*sizeof(struct ifreq);
267 ifc_netconf.ifc_req = a_ifr_ifconf;
269 i_rc = ioctl(i_sockfd, SIOCGIFCONF, (byte_t*)&ifc_netconf);
272 intf_ErrMsg( "net error: cannot read network configuration (%s)",
277 /* If we detected ifc_len interfaces, this may mean that others have
278 been missed because the a_ifr_ifconf was to little, so increase
279 it's size and retry */
280 while( ifc_netconf.ifc_len >= i_if_number*sizeof(struct ifreq) );
282 /* No see what we detected */
285 /* Init the given net_descr_t struct */
286 p_net_descr->i_if_number = 0;
287 p_net_descr->a_if = NULL;
289 /* Iterate through the entries of the a_ifr_ifconf table */
290 p_ifr_current_if = ifc_netconf.ifc_req;
291 for( i_remaining = ifc_netconf.ifc_len / sizeof (struct ifreq);
292 i_remaining-- > 0; p_ifr_current_if++ )
294 intf_DbgMsg("Found interface %s", p_ifr_current_if->ifr_name);
296 /* Don't use an interface devoted to an address family other than IP */
297 if(p_ifr_current_if->ifr_addr.sa_family != AF_INET)
300 /* Read the status of this interface */
301 if( ioctl(i_sockfd, SIOCGIFFLAGS, (byte_t *)p_ifr_current_if) < 0 )
303 intf_ErrMsg( "net error: cannot access interface %s (%s)",
304 p_ifr_current_if->ifr_name, strerror(errno) );
310 /* Skip this interface if it is not up or if this is a loopback one */
311 if( !p_ifr_current_if->ifr_flags & IFF_UP ||
312 p_ifr_current_if->ifr_flags & IFF_LOOPBACK )
315 /* Add an entry to the net_descr struct to store the description of
317 p_net_descr->i_if_number++;
318 p_net_descr->a_if = realloc(p_net_descr->a_if,
319 p_net_descr->i_if_number*sizeof(if_descr_t));
320 /* FIXME: Read the info ?? */
321 i_rc = ReadIfConf(i_sockfd, &p_net_descr->a_if[p_net_descr->i_if_number-1],
322 p_ifr_current_if->ifr_name);
327 /* Don't need the a_ifr_ifconf anymore */
328 free( a_ifr_ifconf );