ncpaddr.c revision 134789
1142425Snectar/*-
2142425Snectar * Copyright (c) 2001 Brian Somers <brian@Awfulhak.org>
3142425Snectar * All rights reserved.
4142425Snectar *
5142425Snectar * Redistribution and use in source and binary forms, with or without
6142425Snectar * modification, are permitted provided that the following conditions
7142425Snectar * are met:
8142425Snectar * 1. Redistributions of source code must retain the above copyright
9142425Snectar *    notice, this list of conditions and the following disclaimer.
10142425Snectar * 2. Redistributions in binary form must reproduce the above copyright
11142425Snectar *    notice, this list of conditions and the following disclaimer in the
12142425Snectar *    documentation and/or other materials provided with the distribution.
13142425Snectar *
14142425Snectar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15142425Snectar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16142425Snectar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17142425Snectar * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18142425Snectar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19142425Snectar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20142425Snectar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21142425Snectar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22160814Ssimon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23238405Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24238405Sjkim * SUCH DAMAGE.
25238405Sjkim *
26142425Snectar * $FreeBSD: head/usr.sbin/ppp/ncpaddr.c 134789 2004-09-05 01:46:52Z brian $
27142425Snectar */
28160814Ssimon
29238405Sjkim#include <sys/types.h>
30238405Sjkim#include <sys/socket.h>
31238405Sjkim#ifdef __OpenBSD__
32142425Snectar#include <net/if_types.h>
33142425Snectar#include <net/route.h>
34142425Snectar#endif
35142425Snectar#include <netinet/in.h>
36142425Snectar#include <netinet/in_systm.h>
37142425Snectar#include <netinet/ip.h>
38142425Snectar#include <arpa/inet.h>
39142425Snectar#include <sys/un.h>
40142425Snectar
41142425Snectar#include <netdb.h>
42142425Snectar#include <stdio.h>
43142425Snectar#include <stdlib.h>
44142425Snectar#include <string.h>
45142425Snectar#include <termios.h>
46238405Sjkim
47142425Snectar#include "log.h"
48142425Snectar#include "ncpaddr.h"
49142425Snectar#include "timer.h"
50142425Snectar#include "fsm.h"
51142425Snectar#include "defs.h"
52142425Snectar#include "slcompress.h"
53142425Snectar#include "iplist.h"
54142425Snectar#include "throughput.h"
55142425Snectar#include "mbuf.h"
56142425Snectar#include "ipcp.h"
57142425Snectar#include "descriptor.h"
58142425Snectar#include "layer.h"
59160814Ssimon#include "lqr.h"
60160814Ssimon#include "hdlc.h"
61142425Snectar#include "lcp.h"
62142425Snectar#include "ccp.h"
63142425Snectar#include "link.h"
64142425Snectar#include "mp.h"
65142425Snectar#include "ipv6cp.h"
66142425Snectar#include "ncp.h"
67142425Snectar
68142425Snectar
69142425Snectar#define ncprange_ip4addr	u.ip4.ipaddr
70142425Snectar#define ncprange_ip4mask	u.ip4.mask
71142425Snectar#define ncprange_ip4width	u.ip4.width
72142425Snectar#define ncpaddr_ip4addr		u.ip4addr
73142425Snectar#ifndef NOINET6
74296341Sdelphij#define ncprange_ip6addr	u.ip6.ipaddr
75296341Sdelphij#define ncprange_ip6width	u.ip6.width
76142425Snectar#define ncpaddr_ip6addr		u.ip6addr
77160814Ssimon#endif
78142425Snectar
79142425Snectar#define	NCP_ASCIIBUFFERSIZE	52
80142425Snectar
81142425Snectarstatic struct in_addr
82142425Snectarbits2mask4(int bits)
83142425Snectar{
84142425Snectar  struct in_addr result;
85142425Snectar  u_int32_t bit = 0x80000000;
86142425Snectar
87142425Snectar  result.s_addr = 0;
88142425Snectar
89194206Ssimon  while (bits) {
90194206Ssimon    result.s_addr |= bit;
91194206Ssimon    bit >>= 1;
92194206Ssimon    bits--;
93194206Ssimon  }
94194206Ssimon
95238405Sjkim  result.s_addr = htonl(result.s_addr);
96238405Sjkim  return result;
97238405Sjkim}
98238405Sjkim
99238405Sjkimstatic int
100238405Sjkimmask42bits(struct in_addr mask)
101238405Sjkim{
102194206Ssimon  u_int32_t msk = ntohl(mask.s_addr);
103194206Ssimon  u_int32_t tst;
104194206Ssimon  int ret;
105194206Ssimon
106194206Ssimon  for (ret = 32, tst = 1; tst; ret--, tst <<= 1)
107142425Snectar    if (msk & tst)
108238405Sjkim      break;
109238405Sjkim
110238405Sjkim  for (tst <<= 1; tst; tst <<= 1)
111238405Sjkim    if (!(msk & tst))
112238405Sjkim      break;
113238405Sjkim
114238405Sjkim  return tst ? -1 : ret;
115238405Sjkim}
116160814Ssimon
117194206Ssimon#ifndef NOINET6
118238405Sjkimstatic struct in6_addr
119194206Ssimonbits2mask6(int bits)
120194206Ssimon{
121238405Sjkim  struct in6_addr result;
122205128Ssimon  u_int32_t bit = 0x80;
123160814Ssimon  u_char *c = result.s6_addr;
124160814Ssimon
125160814Ssimon  memset(&result, '\0', sizeof result);
126194206Ssimon
127238405Sjkim  while (bits) {
128238405Sjkim    if (bit == 0) {
129238405Sjkim      bit = 0x80;
130238405Sjkim      c++;
131194206Ssimon    }
132194206Ssimon    *c |= bit;
133194206Ssimon    bit >>= 1;
134194206Ssimon    bits--;
135194206Ssimon  }
136194206Ssimon
137238405Sjkim  return result;
138238405Sjkim}
139142425Snectar
140194206Ssimonstatic int
141194206Ssimonmask62bits(const struct in6_addr *mask)
142194206Ssimon{
143194206Ssimon  const u_char masks[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
144194206Ssimon  const u_char *c, *p, *end;
145194206Ssimon  int masklen, m;
146194206Ssimon
147194206Ssimon  p = (const u_char *)mask;
148194206Ssimon  for (masklen = 0, end = p + 16; p < end && *p == 0xff; p++)
149142425Snectar    masklen += 8;
150238405Sjkim
151238405Sjkim  if (p < end) {
152238405Sjkim    for (c = masks, m = 0; c < masks + sizeof masks; c++, m++)
153238405Sjkim      if (*c == *p) {
154238405Sjkim        masklen += m;
155238405Sjkim        break;
156238405Sjkim      }
157238405Sjkim  }
158194206Ssimon
159194206Ssimon  return masklen;
160194206Ssimon}
161194206Ssimon
162194206Ssimon#if 0
163238405Sjkimstatic void
164238405Sjkimadjust_linklocal(struct sockaddr_in6 *sin6)
165238405Sjkim{
166238405Sjkim    /* XXX: ?????!?!?!!!!!  This is horrible ! */
167238405Sjkim    /*
168238405Sjkim     * The kernel does not understand sin6_scope_id for routing at this moment.
169238405Sjkim     * We should rather keep the embedded ID.
170238405Sjkim     * jinmei@kame.net, 20011026
171194206Ssimon     */
172194206Ssimon    if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
173194206Ssimon        IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) {
174194206Ssimon      sin6->sin6_scope_id =
175194206Ssimon        ntohs(*(u_short *)&sin6->sin6_addr.s6_addr[2]);
176142425Snectar      *(u_short *)&sin6->sin6_addr.s6_addr[2] = 0;
177238405Sjkim    }
178238405Sjkim}
179238405Sjkim#endif
180238405Sjkim#endif
181238405Sjkim
182238405Sjkimvoid
183238405Sjkimncpaddr_init(struct ncpaddr *addr)
184238405Sjkim{
185194206Ssimon  addr->ncpaddr_family = AF_UNSPEC;
186194206Ssimon}
187194206Ssimon
188194206Ssimonint
189194206Ssimonncpaddr_isset(const struct ncpaddr *addr)
190194206Ssimon{
191238405Sjkim  return addr->ncpaddr_family != AF_UNSPEC;
192238405Sjkim}
193142425Snectar
194194206Ssimonint
195194206Ssimonncpaddr_isdefault(const struct ncpaddr *addr)
196194206Ssimon{
197194206Ssimon  switch (addr->ncpaddr_family) {
198194206Ssimon  case AF_INET:
199194206Ssimon    if (addr->ncpaddr_ip4addr.s_addr == INADDR_ANY)
200194206Ssimon      return 1;
201194206Ssimon    break;
202194206Ssimon
203194206Ssimon#ifndef NOINET6
204238405Sjkim  case AF_INET6:
205238405Sjkim    if (IN6_IS_ADDR_UNSPECIFIED(&addr->ncpaddr_ip6addr))
206238405Sjkim      return 1;
207238405Sjkim    break;
208238405Sjkim#endif
209238405Sjkim  }
210238405Sjkim
211238405Sjkim  return 0;
212194206Ssimon}
213194206Ssimon
214194206Ssimonint
215194206Ssimonncpaddr_equal(const struct ncpaddr *addr, const struct ncpaddr *cmp)
216194206Ssimon{
217194206Ssimon  if (addr->ncpaddr_family != cmp->ncpaddr_family)
218238405Sjkim    return 0;
219238405Sjkim
220142425Snectar  switch (addr->ncpaddr_family) {
221194206Ssimon  case AF_INET:
222194206Ssimon    return addr->ncpaddr_ip4addr.s_addr == cmp->ncpaddr_ip4addr.s_addr;
223194206Ssimon
224194206Ssimon#ifndef NOINET6
225160814Ssimon  case AF_INET6:
226160814Ssimon    return !memcmp(&addr->ncpaddr_ip6addr, &cmp->ncpaddr_ip6addr,
227160814Ssimon                   sizeof addr->ncpaddr_ip6addr);
228142425Snectar#endif
229160814Ssimon
230160814Ssimon  case AF_UNSPEC:
231160814Ssimon    return 1;
232238405Sjkim  }
233238405Sjkim
234142425Snectar  return 0;
235142425Snectar}
236142425Snectar
237142425Snectarvoid
238160814Ssimonncpaddr_copy(struct ncpaddr *addr, const struct ncpaddr *from)
239160814Ssimon{
240160814Ssimon  switch (from->ncpaddr_family) {
241160814Ssimon  case AF_INET:
242160814Ssimon    addr->ncpaddr_family = AF_INET;
243194206Ssimon    addr->ncpaddr_ip4addr = from->ncpaddr_ip4addr;
244194206Ssimon    break;
245194206Ssimon#ifndef NOINET6
246194206Ssimon  case AF_INET6:
247194206Ssimon    addr->ncpaddr_family = AF_INET6;
248194206Ssimon    addr->ncpaddr_ip6addr = from->ncpaddr_ip6addr;
249238405Sjkim    break;
250238405Sjkim#endif
251142425Snectar  default:
252194206Ssimon    addr->ncpaddr_family = AF_UNSPEC;
253194206Ssimon  }
254194206Ssimon}
255194206Ssimon
256238405Sjkimvoid
257238405Sjkimncpaddr_setip4addr(struct ncpaddr *addr, u_int32_t ip)
258238405Sjkim{
259238405Sjkim  addr->ncpaddr_family = AF_INET;
260238405Sjkim  addr->ncpaddr_ip4addr.s_addr = ip;
261238405Sjkim}
262238405Sjkim
263238405Sjkimint
264238405Sjkimncpaddr_getip4addr(const struct ncpaddr *addr, u_int32_t *ip)
265238405Sjkim{
266238405Sjkim  if (addr->ncpaddr_family != AF_INET)
267238405Sjkim    return 0;
268238405Sjkim  *ip = addr->ncpaddr_ip4addr.s_addr;
269238405Sjkim  return 1;
270238405Sjkim}
271238405Sjkim
272238405Sjkimvoid
273238405Sjkimncpaddr_setip4(struct ncpaddr *addr, struct in_addr ip)
274238405Sjkim{
275238405Sjkim  addr->ncpaddr_family = AF_INET;
276238405Sjkim  addr->ncpaddr_ip4addr = ip;
277238405Sjkim}
278238405Sjkim
279238405Sjkimint
280238405Sjkimncpaddr_getip4(const struct ncpaddr *addr, struct in_addr *ip)
281238405Sjkim{
282238405Sjkim  if (addr->ncpaddr_family != AF_INET)
283238405Sjkim    return 0;
284160814Ssimon  *ip = addr->ncpaddr_ip4addr;
285160814Ssimon  return 1;
286160814Ssimon}
287194206Ssimon
288194206Ssimon#ifndef NOINET6
289194206Ssimonvoid
290238405Sjkimncpaddr_setip6(struct ncpaddr *addr, const struct in6_addr *ip6)
291238405Sjkim{
292142425Snectar  addr->ncpaddr_family = AF_INET6;
293142425Snectar  addr->ncpaddr_ip6addr = *ip6;
294194206Ssimon}
295194206Ssimon
296194206Ssimonint
297194206Ssimonncpaddr_getip6(const struct ncpaddr *addr, struct in6_addr *ip6)
298160814Ssimon{
299238405Sjkim  if (addr->ncpaddr_family != AF_INET6)
300238405Sjkim    return 0;
301238405Sjkim  *ip6 = addr->ncpaddr_ip6addr;
302238405Sjkim  return 1;
303238405Sjkim}
304238405Sjkim#endif
305238405Sjkim
306238405Sjkimvoid
307238405Sjkimncpaddr_getsa(const struct ncpaddr *addr, struct sockaddr_storage *host)
308238405Sjkim{
309238405Sjkim  struct sockaddr_in *host4 = (struct sockaddr_in *)host;
310238405Sjkim#ifndef NOINET6
311238405Sjkim  struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host;
312238405Sjkim#endif
313238405Sjkim
314194206Ssimon  memset(host, '\0', sizeof(*host));
315194206Ssimon
316194206Ssimon  switch (addr->ncpaddr_family) {
317194206Ssimon  case AF_INET:
318194206Ssimon    host4->sin_family = AF_INET;
319194206Ssimon    host4->sin_len = sizeof(*host4);
320238405Sjkim    host4->sin_addr = addr->ncpaddr_ip4addr;
321238405Sjkim    break;
322142425Snectar
323142425Snectar#ifndef NOINET6
324194206Ssimon  case AF_INET6:
325194206Ssimon    host6->sin6_family = AF_INET6;
326194206Ssimon    host6->sin6_len = sizeof(*host6);
327194206Ssimon    host6->sin6_addr = addr->ncpaddr_ip6addr;
328160814Ssimon    break;
329194206Ssimon#endif
330160814Ssimon
331194206Ssimon  default:
332194206Ssimon    host->ss_family = AF_UNSPEC;
333194206Ssimon    break;
334238405Sjkim  }
335238405Sjkim}
336238405Sjkim
337238405Sjkimvoid
338238405Sjkimncpaddr_setsa(struct ncpaddr *addr, const struct sockaddr *host)
339238405Sjkim{
340238405Sjkim  const struct sockaddr_in *host4 = (const struct sockaddr_in *)host;
341238405Sjkim#ifndef NOINET6
342194206Ssimon  const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host;
343194206Ssimon#endif
344194206Ssimon
345194206Ssimon  switch (host->sa_family) {
346194206Ssimon  case AF_INET:
347194206Ssimon    addr->ncpaddr_family = AF_INET;
348238405Sjkim    addr->ncpaddr_ip4addr = host4->sin_addr;
349238405Sjkim    break;
350142425Snectar
351142425Snectar#ifndef NOINET6
352194206Ssimon  case AF_INET6:
353194206Ssimon    if (IN6_IS_ADDR_V4MAPPED(&host6->sin6_addr)) {
354194206Ssimon      addr->ncpaddr_family = AF_INET;
355194206Ssimon      addr->ncpaddr_ip4addr.s_addr =
356160814Ssimon        *(const u_int32_t *)(host6->sin6_addr.s6_addr + 12);
357194206Ssimon    } else {
358160814Ssimon      addr->ncpaddr_family = AF_INET6;
359194206Ssimon      addr->ncpaddr_ip6addr = host6->sin6_addr;
360194206Ssimon    }
361194206Ssimon    break;
362238405Sjkim#endif
363238405Sjkim
364238405Sjkim  default:
365238405Sjkim    addr->ncpaddr_family = AF_UNSPEC;
366238405Sjkim  }
367238405Sjkim}
368238405Sjkim
369238405Sjkimstatic char *
370194206Ssimonncpaddr_ntowa(const struct ncpaddr *addr)
371194206Ssimon{
372194206Ssimon  static char res[NCP_ASCIIBUFFERSIZE];
373194206Ssimon#ifndef NOINET6
374194206Ssimon  struct sockaddr_in6 sin6;
375194206Ssimon#endif
376238405Sjkim
377238405Sjkim  switch (addr->ncpaddr_family) {
378238405Sjkim  case AF_INET:
379238405Sjkim    snprintf(res, sizeof res, "%s", inet_ntoa(addr->ncpaddr_ip4addr));
380238405Sjkim    return res;
381238405Sjkim
382238405Sjkim#ifndef NOINET6
383194206Ssimon  case AF_INET6:
384194206Ssimon    memset(&sin6, '\0', sizeof(sin6));
385194206Ssimon    sin6.sin6_len = sizeof(sin6);
386194206Ssimon    sin6.sin6_family = AF_INET6;
387194206Ssimon    sin6.sin6_addr = addr->ncpaddr_ip6addr;
388194206Ssimon#if 0
389238405Sjkim    adjust_linklocal(&sin6);
390238405Sjkim#endif
391160814Ssimon#ifdef NI_WITHSCOPEID
392194206Ssimon    if (getnameinfo((struct sockaddr *)&sin6, sizeof sin6, res, sizeof(res),
393194206Ssimon                    NULL, 0, NI_WITHSCOPEID | NI_NUMERICHOST) != 0)
394194206Ssimon#else
395194206Ssimon    if (getnameinfo((struct sockaddr *)&sin6, sizeof sin6, res, sizeof(res),
396238405Sjkim                    NULL, 0, NI_NUMERICHOST) != 0)
397238405Sjkim#endif
398238405Sjkim      break;
399238405Sjkim
400238405Sjkim    return res;
401238405Sjkim#endif
402238405Sjkim  }
403238405Sjkim
404238405Sjkim  snprintf(res, sizeof res, "<AF_UNSPEC>");
405238405Sjkim  return res;
406238405Sjkim}
407238405Sjkim
408238405Sjkimconst char *
409238405Sjkimncpaddr_ntoa(const struct ncpaddr *addr)
410238405Sjkim{
411194206Ssimon  return ncpaddr_ntowa(addr);
412194206Ssimon}
413194206Ssimon
414194206Ssimon
415194206Ssimonint
416194206Ssimonncpaddr_aton(struct ncpaddr *addr, struct ncp *ncp, const char *data)
417238405Sjkim{
418238405Sjkim  struct ncprange range;
419238405Sjkim
420238405Sjkim  if (!ncprange_aton(&range, ncp, data))
421238405Sjkim    return 0;
422238405Sjkim
423238405Sjkim  if (range.ncprange_family == AF_INET && range.ncprange_ip4width != 32 &&
424194206Ssimon      range.ncprange_ip4addr.s_addr != INADDR_ANY) {
425160814Ssimon    log_Printf(LogWARN, "ncpaddr_aton: %s: Only 32 bits allowed\n", data);
426194206Ssimon    return 0;
427194206Ssimon  }
428194206Ssimon
429238405Sjkim#ifndef NOINET6
430238405Sjkim  if (range.ncprange_family == AF_INET6 && range.ncprange_ip6width != 128 &&
431238405Sjkim      !IN6_IS_ADDR_UNSPECIFIED(&range.ncprange_ip6addr)) {
432238405Sjkim    log_Printf(LogWARN, "ncpaddr_aton: %s: Only 128 bits allowed\n", data);
433238405Sjkim    return 0;
434238405Sjkim  }
435238405Sjkim#endif
436238405Sjkim
437194206Ssimon  switch (range.ncprange_family) {
438194206Ssimon  case AF_INET:
439194206Ssimon    addr->ncpaddr_family = range.ncprange_family;
440194206Ssimon    addr->ncpaddr_ip4addr = range.ncprange_ip4addr;
441194206Ssimon    return 1;
442194206Ssimon
443238405Sjkim#ifndef NOINET6
444238405Sjkim  case AF_INET6:
445160814Ssimon    addr->ncpaddr_family = range.ncprange_family;
446194206Ssimon    addr->ncpaddr_ip6addr = range.ncprange_ip6addr;
447194206Ssimon    return 1;
448194206Ssimon#endif
449194206Ssimon  }
450
451  return 0;
452}
453
454void
455ncprange_init(struct ncprange *range)
456{
457  range->ncprange_family = AF_UNSPEC;
458}
459
460int
461ncprange_isset(const struct ncprange *range)
462{
463  return range->ncprange_family != AF_UNSPEC;
464}
465
466int
467ncprange_equal(const struct ncprange *range, const struct ncprange *cmp)
468{
469  if (range->ncprange_family != cmp->ncprange_family)
470    return 0;
471
472  switch (range->ncprange_family) {
473  case AF_INET:
474    if (range->ncprange_ip4addr.s_addr != cmp->ncprange_ip4addr.s_addr)
475      return 0;
476    return range->ncprange_ip4mask.s_addr == cmp->ncprange_ip4mask.s_addr;
477
478#ifndef NOINET6
479  case AF_INET6:
480    if (range->ncprange_ip6width != cmp->ncprange_ip6width)
481      return 0;
482    return !memcmp(&range->ncprange_ip6addr, &cmp->ncprange_ip6addr,
483                   sizeof range->ncprange_ip6addr);
484#endif
485
486  case AF_UNSPEC:
487    return 1;
488  }
489
490  return 0;
491}
492
493int
494ncprange_isdefault(const struct ncprange *range)
495{
496  switch (range->ncprange_family) {
497  case AF_INET:
498    if (range->ncprange_ip4addr.s_addr == INADDR_ANY)
499      return 1;
500    break;
501
502#ifndef NOINET6
503  case AF_INET6:
504    if (range->ncprange_ip6width == 0 &&
505        IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr))
506      return 1;
507    break;
508#endif
509  }
510
511  return 0;
512}
513
514void
515ncprange_setdefault(struct ncprange *range, int af)
516{
517  memset(range, '\0', sizeof *range);
518  range->ncprange_family = af;
519}
520
521int
522ncprange_contains(const struct ncprange *range, const struct ncpaddr *addr)
523{
524#ifndef NOINET6
525  const u_char masks[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
526  const u_char *addrp, *rangep;
527  int bits;
528#endif
529
530  if (range->ncprange_family != addr->ncpaddr_family)
531    return 0;
532
533  switch (range->ncprange_family) {
534  case AF_INET:
535    return !((addr->ncpaddr_ip4addr.s_addr ^ range->ncprange_ip4addr.s_addr) &
536             range->ncprange_ip4mask.s_addr);
537
538#ifndef NOINET6
539  case AF_INET6:
540    rangep = (const u_char *)range->ncprange_ip6addr.s6_addr;
541    addrp = (const u_char *)addr->ncpaddr_ip6addr.s6_addr;
542
543    for (bits = range->ncprange_ip6width; bits > 0; bits -= 8)
544      if ((*addrp++ ^ *rangep++) & masks[bits > 7 ? 7 : bits - 1])
545        return 0;
546
547    return 1;
548#endif
549  }
550
551  return 0;
552}
553
554int
555ncprange_containsip4(const struct ncprange *range, struct in_addr addr)
556{
557  switch (range->ncprange_family) {
558  case AF_INET:
559    return !((addr.s_addr ^ range->ncprange_ip4addr.s_addr) &
560             range->ncprange_ip4mask.s_addr);
561  }
562
563  return 0;
564}
565
566void
567ncprange_copy(struct ncprange *range, const struct ncprange *from)
568{
569  switch (from->ncprange_family) {
570  case AF_INET:
571    range->ncprange_family = AF_INET;
572    range->ncprange_ip4addr = from->ncprange_ip4addr;
573    range->ncprange_ip4mask = from->ncprange_ip4mask;
574    range->ncprange_ip4width = from->ncprange_ip4width;
575    break;
576
577#ifndef NOINET6
578  case AF_INET6:
579    range->ncprange_family = AF_INET6;
580    range->ncprange_ip6addr = from->ncprange_ip6addr;
581    range->ncprange_ip6width = from->ncprange_ip6width;
582    break;
583#endif
584
585  default:
586    range->ncprange_family = AF_UNSPEC;
587  }
588}
589
590void
591ncprange_set(struct ncprange *range, const struct ncpaddr *addr, int width)
592{
593  ncprange_sethost(range, addr);
594  ncprange_setwidth(range, width);
595}
596
597void
598ncprange_sethost(struct ncprange *range, const struct ncpaddr *from)
599{
600  switch (from->ncpaddr_family) {
601  case AF_INET:
602    range->ncprange_family = AF_INET;
603    range->ncprange_ip4addr = from->ncpaddr_ip4addr;
604    if (from->ncpaddr_ip4addr.s_addr == INADDR_ANY) {
605      range->ncprange_ip4mask.s_addr = INADDR_ANY;
606      range->ncprange_ip4width = 0;
607    } else {
608      range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
609      range->ncprange_ip4width = 32;
610    }
611    break;
612
613#ifndef NOINET6
614  case AF_INET6:
615    range->ncprange_family = AF_INET6;
616    range->ncprange_ip6addr = from->ncpaddr_ip6addr;
617    range->ncprange_ip6width = 128;
618    break;
619#endif
620
621  default:
622    range->ncprange_family = AF_UNSPEC;
623  }
624}
625
626int
627ncprange_ishost(const struct ncprange *range)
628{
629  switch (range->ncprange_family) {
630  case AF_INET:
631    return range->ncprange_ip4width == 32;
632#ifndef NOINET6
633  case AF_INET6:
634    return range->ncprange_ip6width == 128;
635#endif
636  }
637
638  return (0);
639}
640
641int
642ncprange_setwidth(struct ncprange *range, int width)
643{
644  switch (range->ncprange_family) {
645  case AF_INET:
646    if (width < 0 || width > 32)
647      break;
648    range->ncprange_ip4width = width;
649    range->ncprange_ip4mask = bits2mask4(width);
650    break;
651
652#ifndef NOINET6
653  case AF_INET6:
654    if (width < 0 || width > 128)
655      break;
656    range->ncprange_ip6width = width;
657    break;
658#endif
659
660  case AF_UNSPEC:
661    return 1;
662  }
663
664  return 0;
665}
666
667void
668ncprange_setip4host(struct ncprange *range, struct in_addr from)
669{
670  range->ncprange_family = AF_INET;
671  range->ncprange_ip4addr = from;
672  if (from.s_addr == INADDR_ANY) {
673    range->ncprange_ip4mask.s_addr = INADDR_ANY;
674    range->ncprange_ip4width = 0;
675  } else {
676    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
677    range->ncprange_ip4width = 32;
678  }
679}
680
681void
682ncprange_setip4(struct ncprange *range, struct in_addr from, struct in_addr msk)
683{
684  range->ncprange_family = AF_INET;
685  range->ncprange_ip4addr = from;
686  range->ncprange_ip4mask = msk;
687  range->ncprange_ip4width = mask42bits(msk);
688}
689
690
691int
692ncprange_setip4mask(struct ncprange *range, struct in_addr mask)
693{
694  if (range->ncprange_family != AF_INET)
695    return 0;
696  range->ncprange_ip4mask = mask;
697  range->ncprange_ip4width = mask42bits(mask);
698  return 1;
699}
700
701void
702ncprange_setsa(struct ncprange *range, const struct sockaddr *host,
703               const struct sockaddr *mask)
704{
705  const struct sockaddr_in *host4 = (const struct sockaddr_in *)host;
706  const struct sockaddr_in *mask4 = (const struct sockaddr_in *)mask;
707#ifndef NOINET6
708  const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host;
709  const struct sockaddr_in6 *mask6 = (const struct sockaddr_in6 *)mask;
710#endif
711
712  switch (host->sa_family) {
713  case AF_INET:
714    range->ncprange_family = AF_INET;
715    range->ncprange_ip4addr = host4->sin_addr;
716    if (host4->sin_addr.s_addr == INADDR_ANY) {
717      range->ncprange_ip4mask.s_addr = INADDR_ANY;
718      range->ncprange_ip4width = 0;
719    } else if (mask4 && mask4->sin_family == AF_INET) {
720      range->ncprange_ip4mask.s_addr = mask4->sin_addr.s_addr;
721      range->ncprange_ip4width = mask42bits(mask4->sin_addr);
722    } else {
723      range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
724      range->ncprange_ip4width = 32;
725    }
726    break;
727
728#ifndef NOINET6
729  case AF_INET6:
730    range->ncprange_family = AF_INET6;
731    range->ncprange_ip6addr = host6->sin6_addr;
732    if (IN6_IS_ADDR_UNSPECIFIED(&host6->sin6_addr))
733      range->ncprange_ip6width = 0;
734    else
735      range->ncprange_ip6width = mask6 ? mask62bits(&mask6->sin6_addr) : 128;
736    break;
737#endif
738
739  default:
740    range->ncprange_family = AF_UNSPEC;
741  }
742}
743
744void
745ncprange_getsa(const struct ncprange *range, struct sockaddr_storage *host,
746               struct sockaddr_storage *mask)
747{
748  struct sockaddr_in *host4 = (struct sockaddr_in *)host;
749  struct sockaddr_in *mask4 = (struct sockaddr_in *)mask;
750#ifndef NOINET6
751  struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host;
752  struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)mask;
753#endif
754
755  memset(host, '\0', sizeof(*host));
756  if (mask)
757    memset(mask, '\0', sizeof(*mask));
758
759  switch (range->ncprange_family) {
760  case AF_INET:
761    host4->sin_family = AF_INET;
762    host4->sin_len = sizeof(*host4);
763    host4->sin_addr = range->ncprange_ip4addr;
764    if (mask4) {
765      mask4->sin_family = AF_INET;
766      mask4->sin_len = sizeof(*host4);
767      mask4->sin_addr = range->ncprange_ip4mask;
768    }
769    break;
770
771#ifndef NOINET6
772  case AF_INET6:
773    host6->sin6_family = AF_INET6;
774    host6->sin6_len = sizeof(*host6);
775    host6->sin6_addr = range->ncprange_ip6addr;
776    if (mask6) {
777      mask6->sin6_family = AF_INET6;
778      mask6->sin6_len = sizeof(*host6);
779      mask6->sin6_addr = bits2mask6(range->ncprange_ip6width);
780    }
781    break;
782#endif
783
784  default:
785    host->ss_family = AF_UNSPEC;
786    if (mask)
787      mask->ss_family = AF_UNSPEC;
788    break;
789  }
790}
791
792int
793ncprange_getaddr(const struct ncprange *range, struct ncpaddr *addr)
794{
795  switch (range->ncprange_family) {
796  case AF_INET:
797    addr->ncpaddr_family = AF_INET;
798    addr->ncpaddr_ip4addr = range->ncprange_ip4addr;
799    return 1;
800#ifndef NOINET6
801  case AF_INET6:
802    addr->ncpaddr_family = AF_INET6;
803    addr->ncpaddr_ip6addr =  range->ncprange_ip6addr;
804    return 1;
805#endif
806  }
807
808  return 0;
809}
810
811int
812ncprange_getip4addr(const struct ncprange *range, struct in_addr *addr)
813{
814  if (range->ncprange_family != AF_INET)
815    return 0;
816
817  *addr = range->ncprange_ip4addr;
818  return 1;
819}
820
821int
822ncprange_getip4mask(const struct ncprange *range, struct in_addr *mask)
823{
824  switch (range->ncprange_family) {
825  case AF_INET:
826    *mask = range->ncprange_ip4mask;
827    return 1;
828  }
829
830  return 0;
831}
832
833int
834ncprange_getwidth(const struct ncprange *range, int *width)
835{
836  switch (range->ncprange_family) {
837  case AF_INET:
838    *width = range->ncprange_ip4width;
839    return 1;
840#ifndef NOINET6
841  case AF_INET6:
842    *width = range->ncprange_ip6width;
843    return 1;
844#endif
845  }
846
847  return 0;
848}
849
850const char *
851ncprange_ntoa(const struct ncprange *range)
852{
853  char *res;
854  struct ncpaddr addr;
855  int len;
856
857  if (!ncprange_getaddr(range, &addr))
858    return "<AF_UNSPEC>";
859
860  res = ncpaddr_ntowa(&addr);
861  len = strlen(res);
862  if (len >= NCP_ASCIIBUFFERSIZE - 1)
863    return res;
864
865  switch (range->ncprange_family) {
866  case AF_INET:
867    if (range->ncprange_ip4width == -1) {
868      /* A non-contiguous mask */
869      for (; len >= 3; res[len -= 2] = '\0')
870        if (strcmp(res + len - 2, ".0"))
871          break;
872      snprintf(res + len, sizeof res - len, "&0x%08lx",
873               (unsigned long)ntohl(range->ncprange_ip4mask.s_addr));
874    } else if (range->ncprange_ip4width < 32)
875      snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip4width);
876
877    return res;
878
879#ifndef NOINET6
880  case AF_INET6:
881    if (range->ncprange_ip6width != 128)
882      snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip6width);
883
884    return res;
885#endif
886  }
887
888  return "<AF_UNSPEC>";
889}
890
891#ifndef NOINET6
892int
893ncprange_scopeid(const struct ncprange *range)
894{
895  const struct in6_addr *sin6;
896  int scopeid = -1;
897
898  if (range->ncprange_family == AF_INET6) {
899    sin6 = &range->ncprange_ip6addr;
900    if (IN6_IS_ADDR_LINKLOCAL(sin6) || IN6_IS_ADDR_MC_LINKLOCAL(sin6))
901      if ((scopeid = ntohs(*(const u_short *)&sin6->s6_addr[2])) == 0)
902        scopeid = -1;
903  }
904
905  return scopeid;
906}
907#endif
908
909int
910ncprange_aton(struct ncprange *range, struct ncp *ncp, const char *data)
911{
912  int bits, len;
913  char *wp;
914  const char *cp;
915  char *s;
916
917  len = strcspn(data, "/");
918
919  if (ncp && strncasecmp(data, "HISADDR", len) == 0) {
920    range->ncprange_family = AF_INET;
921    range->ncprange_ip4addr = ncp->ipcp.peer_ip;
922    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
923    range->ncprange_ip4width = 32;
924    return 1;
925#ifndef NOINET6
926  } else if (ncp && strncasecmp(data, "HISADDR6", len) == 0) {
927    range->ncprange_family = AF_INET6;
928    range->ncprange_ip6addr = ncp->ipv6cp.hisaddr.ncpaddr_ip6addr;
929    range->ncprange_ip6width = 128;
930    return 1;
931#endif
932  } else if (ncp && strncasecmp(data, "MYADDR", len) == 0) {
933    range->ncprange_family = AF_INET;
934    range->ncprange_ip4addr = ncp->ipcp.my_ip;
935    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
936    range->ncprange_ip4width = 32;
937    return 1;
938#ifndef NOINET6
939  } else if (ncp && strncasecmp(data, "MYADDR6", len) == 0) {
940    range->ncprange_family = AF_INET6;
941    range->ncprange_ip6addr = ncp->ipv6cp.myaddr.ncpaddr_ip6addr;
942    range->ncprange_ip6width = 128;
943    return 1;
944#endif
945  } else if (ncp && strncasecmp(data, "DNS0", len) == 0) {
946    range->ncprange_family = AF_INET;
947    range->ncprange_ip4addr = ncp->ipcp.ns.dns[0];
948    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
949    range->ncprange_ip4width = 32;
950    return 1;
951  } else if (ncp && strncasecmp(data, "DNS1", len) == 0) {
952    range->ncprange_family = AF_INET;
953    range->ncprange_ip4addr = ncp->ipcp.ns.dns[1];
954    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
955    range->ncprange_ip4width = 32;
956    return 1;
957  }
958
959  s = (char *)alloca(len + 1);
960  strncpy(s, data, len);
961  s[len] = '\0';
962  bits = -1;
963
964  if (data[len] != '\0') {
965    bits = strtol(data + len + 1, &wp, 0);
966    if (*wp || wp == data + len + 1 || bits < 0 || bits > 128) {
967      log_Printf(LogWARN, "ncprange_aton: bad mask width.\n");
968      return 0;
969    }
970  }
971
972  if ((cp = strchr(data, ':')) == NULL) {
973    range->ncprange_family = AF_INET;
974
975    range->ncprange_ip4addr = GetIpAddr(s);
976
977    if (range->ncprange_ip4addr.s_addr == INADDR_NONE) {
978      log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s);
979      return 0;
980    }
981
982    if (range->ncprange_ip4addr.s_addr == INADDR_ANY) {
983      range->ncprange_ip4mask.s_addr = INADDR_ANY;
984      range->ncprange_ip4width = 0;
985    } else if (bits == -1) {
986      range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
987      range->ncprange_ip4width = 32;
988    } else if (bits > 32) {
989      log_Printf(LogWARN, "ncprange_aton: bad mask width.\n");
990      return 0;
991    } else {
992      range->ncprange_ip4mask = bits2mask4(bits);
993      range->ncprange_ip4width = bits;
994    }
995
996    return 1;
997#ifndef NOINET6
998  } else if (strchr(cp + 1, ':') != NULL) {
999    range->ncprange_family = AF_INET6;
1000
1001    if (inet_pton(AF_INET6, s, &range->ncprange_ip6addr) != 1) {
1002      log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s);
1003      return 0;
1004    }
1005
1006    if (IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr))
1007      range->ncprange_ip6width = 0;
1008    else
1009      range->ncprange_ip6width = (bits == -1) ? 128 : bits;
1010    return 1;
1011#endif
1012  }
1013
1014  return 0;
1015}
1016