~ubuntu-branches/ubuntu/breezy/quagga/breezy-security

« back to all changes in this revision

Viewing changes to zebra/if_ioctl_solaris.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Mueller
  • Date: 2005-05-20 13:16:12 UTC
  • Revision ID: james.westby@ubuntu.com-20050520131612-pr6paalox60o3x3n
Tags: upstream-0.99.1
ImportĀ upstreamĀ versionĀ 0.99.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Interface looking up by ioctl () on Solaris.
 
3
 * Copyright (C) 1997, 98 Kunihiro Ishiguro
 
4
 *
 
5
 * This file is part of GNU Zebra.
 
6
 *
 
7
 * GNU Zebra is free software; you can redistribute it and/or modify it
 
8
 * under the terms of the GNU General Public License as published by the
 
9
 * Free Software Foundation; either version 2, or (at your option) any
 
10
 * later version.
 
11
 *
 
12
 * GNU Zebra is distributed in the hope that it will be useful, but
 
13
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15
 * General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with GNU Zebra; see the file COPYING.  If not, write to the Free
 
19
 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
20
 * 02111-1307, USA.  
 
21
 */
 
22
 
 
23
#include <zebra.h>
 
24
 
 
25
#include "if.h"
 
26
#include "sockunion.h"
 
27
#include "prefix.h"
 
28
#include "ioctl.h"
 
29
#include "connected.h"
 
30
#include "memory.h"
 
31
#include "log.h"
 
32
#include "privs.h"
 
33
 
 
34
#include "zebra/interface.h"
 
35
 
 
36
void lifreq_set_name (struct lifreq *, struct interface *);
 
37
static int if_get_addr (struct interface *, struct sockaddr *);
 
38
static void interface_info_ioctl (struct interface *);
 
39
extern struct zebra_privs_t zserv_privs;
 
40
 
 
41
int
 
42
interface_list_ioctl (int af)
 
43
{
 
44
  int ret;
 
45
  int sock;
 
46
#define IFNUM_BASE 32
 
47
  struct lifnum lifn;
 
48
  int ifnum;
 
49
  struct lifreq *lifreq;
 
50
  struct lifconf lifconf;
 
51
  struct interface *ifp;
 
52
  int n;
 
53
  int save_errno;
 
54
  size_t needed, lastneeded = 0;
 
55
  char *buf = NULL;
 
56
 
 
57
  if (zserv_privs.change(ZPRIVS_RAISE))
 
58
    zlog (NULL, LOG_ERR, "Can't raise privileges");
 
59
  
 
60
  sock = socket (af, SOCK_DGRAM, 0);
 
61
  if (sock < 0)
 
62
    {
 
63
      zlog_warn ("Can't make %s socket stream: %s",
 
64
                 (af == AF_INET ? "AF_INET" : "AF_INET6"), safe_strerror (errno));
 
65
                 
 
66
      if (zserv_privs.change(ZPRIVS_LOWER))
 
67
        zlog (NULL, LOG_ERR, "Can't lower privileges");
 
68
        
 
69
      return -1;
 
70
    }
 
71
 
 
72
calculate_lifc_len:     /* must hold privileges to enter here */
 
73
  lifn.lifn_family = af;
 
74
  lifn.lifn_flags = 0;
 
75
  ret = ioctl (sock, SIOCGLIFNUM, &lifn);
 
76
  save_errno = errno;
 
77
  
 
78
  if (zserv_privs.change(ZPRIVS_LOWER))
 
79
    zlog (NULL, LOG_ERR, "Can't lower privileges");
 
80
 
 
81
  if (ret < 0)
 
82
    {
 
83
      zlog_warn ("interface_list_ioctl: SIOCGLIFNUM failed %s",
 
84
                 safe_strerror (save_errno));
 
85
      close (sock);
 
86
      return -1;
 
87
    }
 
88
  ifnum = lifn.lifn_count;
 
89
 
 
90
  /*
 
91
   * When calculating the buffer size needed, add a small number
 
92
   * of interfaces to those we counted.  We do this to capture
 
93
   * the interface status of potential interfaces which may have
 
94
   * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
 
95
   */
 
96
  needed = (ifnum + 4) * sizeof (struct lifreq);
 
97
  if (needed > lastneeded || needed < lastneeded / 2)
 
98
    {
 
99
      if (buf != NULL)
 
100
        XFREE (MTYPE_TMP, buf);
 
101
      if ((buf = XMALLOC (MTYPE_TMP, needed)) == NULL)
 
102
        {
 
103
          zlog_warn ("interface_list_ioctl: malloc failed");
 
104
          close (sock);
 
105
          return -1;
 
106
        }
 
107
    }
 
108
  lastneeded = needed;
 
109
 
 
110
  lifconf.lifc_family = af;
 
111
  lifconf.lifc_flags = 0;
 
112
  lifconf.lifc_len = needed;
 
113
  lifconf.lifc_buf = buf;
 
114
 
 
115
  if (zserv_privs.change(ZPRIVS_RAISE))
 
116
    zlog (NULL, LOG_ERR, "Can't raise privileges");
 
117
    
 
118
  ret = ioctl (sock, SIOCGLIFCONF, &lifconf);
 
119
 
 
120
  if (ret < 0)
 
121
    {
 
122
      if (errno == EINVAL)
 
123
        goto calculate_lifc_len; /* deliberately hold privileges */
 
124
 
 
125
      zlog_warn ("SIOCGLIFCONF: %s", safe_strerror (errno));
 
126
 
 
127
      if (zserv_privs.change(ZPRIVS_LOWER))
 
128
        zlog (NULL, LOG_ERR, "Can't lower privileges");
 
129
 
 
130
      goto end;
 
131
    }
 
132
 
 
133
  if (zserv_privs.change(ZPRIVS_LOWER))
 
134
    zlog (NULL, LOG_ERR, "Can't lower privileges");
 
135
    
 
136
  /* Allocate interface. */
 
137
  lifreq = lifconf.lifc_req;
 
138
 
 
139
  for (n = 0; n < lifconf.lifc_len; n += sizeof (struct lifreq))
 
140
    {
 
141
      ifp = if_get_by_name_len(lifreq->lifr_name,
 
142
                               strnlen(lifreq->lifr_name,
 
143
                                       sizeof(lifreq->lifr_name)));
 
144
 
 
145
      if (lifreq->lifr_addr.ss_family == AF_INET)
 
146
        ifp->flags |= IFF_IPV4;
 
147
 
 
148
      if (lifreq->lifr_addr.ss_family == AF_INET6)
 
149
        {
 
150
#ifdef HAVE_IPV6
 
151
          ifp->flags |= IFF_IPV6;
 
152
#else
 
153
          lifreq++;
 
154
          continue;
 
155
#endif /* HAVE_IPV6 */
 
156
        }
 
157
        
 
158
      if_add_update (ifp);
 
159
 
 
160
      interface_info_ioctl (ifp);
 
161
      if_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr);
 
162
      lifreq++;
 
163
    }
 
164
 
 
165
end:
 
166
  close (sock);
 
167
  XFREE (MTYPE_TMP, lifconf.lifc_buf);
 
168
  return ret;
 
169
}
 
170
 
 
171
/* Get interface's index by ioctl. */
 
172
int
 
173
if_get_index (struct interface *ifp)
 
174
{
 
175
  int ret;
 
176
  struct lifreq lifreq;
 
177
 
 
178
  lifreq_set_name (&lifreq, ifp);
 
179
 
 
180
  if (ifp->flags & IFF_IPV4)
 
181
    ret = AF_IOCTL (AF_INET, SIOCGLIFINDEX, (caddr_t) & lifreq);
 
182
  else if (ifp->flags & IFF_IPV6)
 
183
    ret = AF_IOCTL (AF_INET6, SIOCGLIFINDEX, (caddr_t) & lifreq);
 
184
  else
 
185
    ret = -1;
 
186
 
 
187
  if (ret < 0)
 
188
    {
 
189
      zlog_warn ("SIOCGLIFINDEX(%s) failed", ifp->name);
 
190
      return ret;
 
191
    }
 
192
 
 
193
  /* OK we got interface index. */
 
194
#ifdef ifr_ifindex
 
195
  ifp->ifindex = lifreq.lifr_ifindex;
 
196
#else
 
197
  ifp->ifindex = lifreq.lifr_index;
 
198
#endif
 
199
  return ifp->ifindex;
 
200
 
 
201
}
 
202
 
 
203
 
 
204
/* Interface address lookup by ioctl.  This function only looks up
 
205
   IPv4 address. */
 
206
#define ADDRLEN(sa) (((sa)->sa_family == AF_INET ?  \
 
207
                sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6)))
 
208
 
 
209
#define SIN(s) ((struct sockaddr_in *)(s))
 
210
#define SIN6(s) ((struct sockaddr_in6 *)(s))
 
211
 
 
212
static int
 
213
if_get_addr (struct interface *ifp, struct sockaddr *addr)
 
214
{
 
215
  int ret;
 
216
  struct lifreq lifreq;
 
217
  struct sockaddr_storage mask, dest;
 
218
  char *dest_pnt = NULL;
 
219
  u_char prefixlen = 0;
 
220
  afi_t af;
 
221
 
 
222
  /* Interface's name and address family. */
 
223
  strncpy (lifreq.lifr_name, ifp->name, IFNAMSIZ);
 
224
 
 
225
  /* Interface's address. */
 
226
  memcpy (&lifreq.lifr_addr, addr, ADDRLEN (addr));
 
227
  af = addr->sa_family;
 
228
 
 
229
  /* Point to point or broad cast address pointer init. */
 
230
  dest_pnt = NULL;
 
231
 
 
232
  if (ifp->flags & IFF_POINTOPOINT)
 
233
    {
 
234
      ret = AF_IOCTL (af, SIOCGLIFDSTADDR, (caddr_t) & lifreq);
 
235
        
 
236
      if (ret < 0)
 
237
        {
 
238
          zlog_warn ("SIOCGLIFDSTADDR (%s) fail: %s",
 
239
                     ifp->name, safe_strerror (errno));
 
240
          return ret;
 
241
        }
 
242
      memcpy (&dest, &lifreq.lifr_dstaddr, ADDRLEN (addr));
 
243
      if (af == AF_INET)
 
244
        dest_pnt = (char *) &(SIN (&dest)->sin_addr);
 
245
      else
 
246
        dest_pnt = (char *) &(SIN6 (&dest)->sin6_addr);
 
247
    }
 
248
 
 
249
  if (af == AF_INET)
 
250
    {
 
251
      ret = if_ioctl (SIOCGLIFNETMASK, (caddr_t) & lifreq);
 
252
      
 
253
      if (ret < 0)
 
254
        {
 
255
          if (errno != EADDRNOTAVAIL)
 
256
            {
 
257
              zlog_warn ("SIOCGLIFNETMASK (%s) fail: %s", ifp->name,
 
258
                         safe_strerror (errno));
 
259
              return ret;
 
260
            }
 
261
          return 0;
 
262
        }
 
263
      memcpy (&mask, &lifreq.lifr_addr, ADDRLEN (addr));
 
264
 
 
265
      prefixlen = ip_masklen (SIN (&mask)->sin_addr);
 
266
      if (ifp->flags & IFF_BROADCAST)
 
267
        {
 
268
          ret = if_ioctl (SIOCGLIFBRDADDR, (caddr_t) & lifreq);
 
269
          if (ret < 0)
 
270
            {
 
271
              if (errno != EADDRNOTAVAIL)
 
272
                {
 
273
                  zlog_warn ("SIOCGLIFBRDADDR (%s) fail: %s",
 
274
                             ifp->name, safe_strerror (errno));
 
275
                  return ret;
 
276
                }
 
277
              return 0;
 
278
            }
 
279
          memcpy (&dest, &lifreq.lifr_broadaddr, sizeof (struct sockaddr_in));
 
280
          dest_pnt = (char *) &SIN (&dest)->sin_addr;
 
281
        }
 
282
    }
 
283
#ifdef HAVE_IPV6
 
284
  else if (af == AF_INET6)
 
285
    {
 
286
      if (ifp->flags & IFF_POINTOPOINT)
 
287
        {
 
288
          prefixlen = IPV6_MAX_BITLEN;
 
289
        }
 
290
      else
 
291
        {
 
292
          ret = if_ioctl_ipv6 (SIOCGLIFSUBNET, (caddr_t) & lifreq);
 
293
          if (ret < 0)
 
294
            {
 
295
              zlog_warn ("SIOCGLIFSUBNET (%s) fail: %s",
 
296
                         ifp->name, safe_strerror (errno));
 
297
            }
 
298
          else
 
299
            {
 
300
              prefixlen = lifreq.lifr_addrlen;
 
301
            }
 
302
        }
 
303
    }
 
304
#endif /* HAVE_IPV6 */
 
305
 
 
306
  /* Set address to the interface. */
 
307
  if (af == AF_INET)
 
308
    connected_add_ipv4 (ifp, 0, &SIN (addr)->sin_addr, prefixlen,
 
309
                        (struct in_addr *) dest_pnt, NULL);
 
310
#ifdef HAVE_IPV6
 
311
  else if (af == AF_INET6)
 
312
    connected_add_ipv6 (ifp, &SIN6 (addr)->sin6_addr, prefixlen,
 
313
                        (struct in6_addr *) dest_pnt);
 
314
#endif /* HAVE_IPV6 */
 
315
 
 
316
  return 0;
 
317
}
 
318
 
 
319
/* Fetch interface information via ioctl(). */
 
320
static void
 
321
interface_info_ioctl (struct interface *ifp)
 
322
{
 
323
  if_get_index (ifp);
 
324
  if_get_flags (ifp);
 
325
  if_get_mtu (ifp);
 
326
  if_get_metric (ifp);
 
327
}
 
328
 
 
329
/* Lookup all interface information. */
 
330
void
 
331
interface_list ()
 
332
{
 
333
  interface_list_ioctl (AF_INET);
 
334
  interface_list_ioctl (AF_INET6);
 
335
}
 
336
 
 
337
struct connected *
 
338
if_lookup_linklocal (struct interface *ifp)
 
339
{
 
340
#ifdef HAVE_IPV6
 
341
  struct listnode *node;
 
342
  struct connected *ifc;
 
343
 
 
344
  if (ifp == NULL)
 
345
    return NULL;
 
346
 
 
347
  for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc))
 
348
    {
 
349
      if ((ifc->address->family == AF_INET6) &&
 
350
          (IN6_IS_ADDR_LINKLOCAL (&ifc->address->u.prefix6)))
 
351
        return ifc;
 
352
    }
 
353
#endif /* HAVE_IPV6 */
 
354
 
 
355
  return NULL;
 
356
}