netutils.c 11.7 KB
Newer Older
1
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
2
 * netutils.c: various network functions
3
 *****************************************************************************
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 * Copyright (C) 1999, 2000 VideoLAN
 *
 * Authors:
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
22
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
23

24
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
25
 * Preamble
26
 *****************************************************************************/
27
28
#include "defs.h"

29
30
31
32
#include <netdb.h>                                        /* gethostbyname() */
#include <stdlib.h>                             /* free(), realloc(), atoi() */
#include <errno.h>                                                /* errno() */
#include <string.h>                                      /* bzero(), bcopy() */
33

34
35
#include <netinet/in.h>                               /* BSD: struct in_addr */
#include <sys/socket.h>                              /* BSD: struct sockaddr */
36
#ifdef HAVE_ARPA_INET_H
37
38
39
#include <arpa/inet.h>                           /* inet_ntoa(), inet_aton() */
#endif

40
#if defined (HAVE_SYS_IOCTL_H) && defined (HAVE_NET_IF_H)
41
#include <sys/ioctl.h>                                            /* ioctl() */
42
43
#include <net/if.h>                            /* interface (arch-dependent) */
#endif
Michel Kaempf's avatar
Michel Kaempf committed
44
45
46
47
48
49
50
51
52
53

#include "config.h"
#include "common.h"
#include "mtime.h"

#include "intf_msg.h"
#include "debug.h"

#include "netutils.h"

54
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
55
 * BuildInetAddr: build an Internet address descriptor
56
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
57
58
59
60
 * Build an internet socket descriptor from a host name, or an ip, and a port.
 * If the address is NULL, then INADDR_ANY will be used, allowing to receive
 * on any address for a local socket. Usually, in this case, 'port' is also null
 * and the function always succeeds.
61
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
62
63
int BuildInetAddr( struct sockaddr_in *p_sa_in, char *psz_in_addr, int i_port )
{
64
    struct hostent *p_hostent;                            /* host descriptor */
Michel Kaempf's avatar
Michel Kaempf committed
65

66
    memset( p_sa_in, 0, sizeof( struct sockaddr_in ) );
67
68
    p_sa_in->sin_family = AF_INET;                                 /* family */
    p_sa_in->sin_port = htons( i_port );                             /* port */
Michel Kaempf's avatar
Michel Kaempf committed
69
70
71

    /* Use INADDR_ANY if psz_in_addr is NULL */
    if( psz_in_addr == NULL )
72
    {
Michel Kaempf's avatar
Michel Kaempf committed
73
        p_sa_in->sin_addr.s_addr = htonl(INADDR_ANY);
74
75
76
    }
    /* Try to convert address directly from in_addr - this will work if
     * psz_in_addr is dotted decimal. */
77
#ifdef HAVE_ARPA_INET_H
Michel Kaempf's avatar
Michel Kaempf committed
78
    else if( !inet_aton( psz_in_addr, &p_sa_in->sin_addr) )
79
80
#else
    else if( (p_sa_in->sin_addr.s_addr = inet_addr( psz_in_addr )) == -1 )
81
#endif
Michel Kaempf's avatar
Michel Kaempf committed
82
83
84
    {
        /* The convertion failed: the address is an host name, which needs
         * to be resolved */
85
        intf_DbgMsg("debug: resolving internet address %s...\n", psz_in_addr);
Michel Kaempf's avatar
Michel Kaempf committed
86
87
88
        if ( (p_hostent = gethostbyname(psz_in_addr)) == NULL)
        {
            intf_ErrMsg("error: unknown host %s\n", psz_in_addr);
89
            return( -1 );
Michel Kaempf's avatar
Michel Kaempf committed
90
91
92
        }

        /* Copy the first address of the host in the socket address */
93
        memmove( &p_sa_in->sin_addr, p_hostent->h_addr_list[0], p_hostent->h_length );
Michel Kaempf's avatar
Michel Kaempf committed
94
    }
95
    return( 0 );
Michel Kaempf's avatar
Michel Kaempf committed
96
97
98
}


99
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
100
 * ServerPort: extract port from a "server:port" adress
101
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
102
103
 * Returns the port number in a "server:port" address and replace the ":" by
 * a NUL character, or returns -1.
104
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
105
106
107
108
109
110
111
112
int ServerPort( char *psz_addr )
{
    char *psz_index;

    /* Scan string for ':' */
    for( psz_index = psz_addr; *psz_index && (*psz_index != ':'); psz_index++ )
    {
        ;
113
114
    }

Michel Kaempf's avatar
Michel Kaempf committed
115
116
117
118
119
120
121
    /* If a port number has been found, convert it and return it */
    if( *psz_index == ':' )
    {
        *psz_index = '\0';
        return( atoi( psz_index + 1 ) );
    }

122
    return( - 1 );
Michel Kaempf's avatar
Michel Kaempf committed
123
124
125
}


126
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
127
 * ReadIfConf: Read the configuration of an interface
128
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
129
 * i_sockfd must reference a socket open as follow: AF_INET, DOCK_DGRAM, 0
130
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
131
int ReadIfConf(int i_sockfd, if_descr_t* p_ifdescr, char* psz_name)
132
{
Michel Kaempf's avatar
Michel Kaempf committed
133
    int i_rc = 0;
134
#if defined (HAVE_SYS_IOCTL_H) && defined(HAVE_NET_IF_H)
135
    struct ifreq ifr_config;
136

Michel Kaempf's avatar
Michel Kaempf committed
137
138
    ASSERT(p_ifdescr);
    ASSERT(psz_name);
139

Michel Kaempf's avatar
Michel Kaempf committed
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
    /* Which interface are we interested in ? */
    strcpy(ifr_config.ifr_name, psz_name);

    /* Read the flags for that interface */
    i_rc = ioctl(i_sockfd, SIOCGIFFLAGS, (byte_t *)&ifr_config);
    if( !i_rc )
    {
        p_ifdescr->i_flags = ifr_config.ifr_flags;
        intf_DbgMsg("%s flags: 0x%x\n", psz_name, p_ifdescr->i_flags);
    }
    else
    {
        intf_ErrMsg("Cannot read flags for interface %s: %s\n", psz_name,
                    strerror(errno));
        return -1;
    }

157
   /* Read physical address of the interface and store it in our description */
Michel Kaempf's avatar
Michel Kaempf committed
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
    i_rc = ioctl(i_sockfd, SIOCGIFHWADDR, (byte_t *)&ifr_config);
    if( !i_rc )
    {
        memcpy(&p_ifdescr->sa_phys_addr, &ifr_config.ifr_addr, sizeof(struct sockaddr));
        intf_DbgMsg("%s MAC address: %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", psz_name,
                    p_ifdescr->sa_phys_addr.sa_data[0]&0xff,
                    p_ifdescr->sa_phys_addr.sa_data[1]&0xff,
                    p_ifdescr->sa_phys_addr.sa_data[2]&0xff,
                    p_ifdescr->sa_phys_addr.sa_data[3]&0xff,
                    p_ifdescr->sa_phys_addr.sa_data[4]&0xff,
                    p_ifdescr->sa_phys_addr.sa_data[5]&0xff);
    }
    else
    {
        intf_ErrMsg("Cannot read hardware address for interface %s: %s\n",
                    psz_name, strerror(errno));
        return -1;
    }
176

Michel Kaempf's avatar
Michel Kaempf committed
177
178
179
180
181
182
183
184
185
186
187
188
189
190
    /* Read IP address of the interface and store it in our description */
    i_rc = ioctl(i_sockfd, SIOCGIFADDR, (byte_t *)&ifr_config);
    if( !i_rc )
    {
        memcpy(&p_ifdescr->sa_net_addr, &ifr_config.ifr_addr, sizeof(struct sockaddr));
        intf_DbgMsg("%s IP address: %s\n", psz_name,
                    inet_ntoa(p_ifdescr->sa_net_addr.sin_addr));
    }
    else
    {
        intf_ErrMsg("Cannot read network address for interface %s: %s\n",
                    psz_name, strerror(errno));
        return -1;
    }
191
192

  /* Read broadcast address of the interface and store it in our description */
Michel Kaempf's avatar
Michel Kaempf committed
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
    if(p_ifdescr->i_flags & IFF_POINTOPOINT)
    {
        intf_DbgMsg("%s doen't not support broadcast\n", psz_name);
        i_rc = ioctl(i_sockfd, SIOCGIFDSTADDR, (byte_t *)&ifr_config);
    }
    else
    {
        intf_DbgMsg("%s supports broadcast\n", psz_name);
        i_rc = ioctl(i_sockfd, SIOCGIFBRDADDR, (byte_t *)&ifr_config);
    }
    if( !i_rc )
    {
        memcpy(&p_ifdescr->sa_bcast_addr, &ifr_config.ifr_addr, sizeof(struct sockaddr));
        intf_DbgMsg("%s broadcast address: %s\n", psz_name,
                    inet_ntoa(p_ifdescr->sa_bcast_addr.sin_addr));
    }
    else
    {
        intf_ErrMsg("Cannot read broadcast address for interface %s: %s\n",
                    psz_name, strerror(errno));
        return -1;
    }
215
#endif
216

Michel Kaempf's avatar
Michel Kaempf committed
217
218
219
220
221
    return i_rc;
}



222
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
223
 * ReadNetConf: Retrieve the network configuration of the host
224
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
225
226
 * Only IP interfaces are listed, and only if they are up
 * i_sockfd must reference a socket open as follow: AF_INET, DOCK_DGRAM, 0
227
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
228
229
int ReadNetConf(int i_sockfd, net_descr_t* p_net_descr)
{
230
#if defined (HAVE_SYS_IOCTL_H) && defined (HAVE_NET_IF_H)
Michel Kaempf's avatar
Michel Kaempf committed
231
232
233
    struct ifreq* a_ifr_ifconf = NULL;
    struct ifreq* p_ifr_current_if;
    struct ifconf ifc_netconf;
234

Michel Kaempf's avatar
Michel Kaempf committed
235
236
    int i_if_number;
    int i_remaining;
237
#endif
Michel Kaempf's avatar
Michel Kaempf committed
238
239
    int i_rc = 0;

240
#if defined (HAVE_SYS_IOCTL_H) && defined (HAVE_NET_IF_H)
Michel Kaempf's avatar
Michel Kaempf committed
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
    ASSERT(p_net_descr);

    /* Start by assuming we have few than 3 interfaces (i_if_number will
       be incremented by 1 when entering the loop) */
    i_if_number = 2;

    /* Retrieve network configuration for that host */
    do
    {
        i_if_number++;
        a_ifr_ifconf = realloc(a_ifr_ifconf, i_if_number*sizeof(struct ifreq));
        ifc_netconf.ifc_len = i_if_number*sizeof(struct ifreq);
        ifc_netconf.ifc_req = a_ifr_ifconf;

        i_rc = ioctl(i_sockfd, SIOCGIFCONF, (byte_t*)&ifc_netconf);
        if( i_rc )
        {
            intf_ErrMsg("Cannot read network configuration: %s\n",
                        strerror(errno));
            break;
        }
    }
    /* If we detected ifc_len interfaces, this may mean that others have
       been missed because the a_ifr_ifconf was to little, so increase
       it's size and retry */
    while( ifc_netconf.ifc_len >= i_if_number*sizeof(struct ifreq) );

    /* No see what we detected */
    if( !i_rc )
    {
        /* Init the given net_descr_t struct */
        p_net_descr->i_if_number = 0;
        p_net_descr->a_if = NULL;

        /* Iterate through the entries of the a_ifr_ifconf table */
        p_ifr_current_if = ifc_netconf.ifc_req;
        for( i_remaining = ifc_netconf.ifc_len / sizeof (struct ifreq);
             i_remaining-- > 0; p_ifr_current_if++ )
        {
            intf_DbgMsg("Found interface %s\n", p_ifr_current_if->ifr_name);

            /* Don't use an interface devoted to an address family other than IP */
            if(p_ifr_current_if->ifr_addr.sa_family != AF_INET)
                continue;

            /* Read the status of this interface */
            if( ioctl(i_sockfd, SIOCGIFFLAGS, (byte_t *)p_ifr_current_if) < 0 )
            {
                intf_ErrMsg("Cannot access interface %s: %s\n",
                            p_ifr_current_if->ifr_name, strerror(errno));
                i_rc = -1;
                break;
            }
            else
            {
                /* Skip this interface if it is not up or if this is a loopback one */
                if( !p_ifr_current_if->ifr_flags & IFF_UP ||
                    p_ifr_current_if->ifr_flags & IFF_LOOPBACK )
                  continue;

                /* Add an entry to the net_descr struct to store the description of
                   that interface */
                p_net_descr->i_if_number++;
                p_net_descr->a_if = realloc(p_net_descr->a_if,
                                            p_net_descr->i_if_number*sizeof(if_descr_t));
306
                /* FIXME: Read the info ?? */
Michel Kaempf's avatar
Michel Kaempf committed
307
308
309
310
311
                i_rc = ReadIfConf(i_sockfd, &p_net_descr->a_if[p_net_descr->i_if_number-1],
                                  p_ifr_current_if->ifr_name);
            }
        }
    }
312

Michel Kaempf's avatar
Michel Kaempf committed
313
314
    /* Don't need the a_ifr_ifconf anymore */
    free( a_ifr_ifconf );
315
#endif
316

Michel Kaempf's avatar
Michel Kaempf committed
317
318
319
320
    return i_rc;
}