1/*	$NetBSD: alist_new.c,v 1.1.1.2 2012/07/22 13:44:38 darrenr Exp $	*/
2
3/*
4 * Copyright (C) 2012 by Darren Reed.
5 *
6 * See the IPFILTER.LICENCE file for details on licencing.
7 *
8 * Id: alist_new.c,v 1.1.1.2 2012/07/22 13:44:38 darrenr Exp $
9 */
10
11#include "ipf.h"
12#include <ctype.h>
13
14alist_t *
15alist_new(int family, char *host)
16{
17	int a, b, c, d, bits;
18	char *slash;
19	alist_t *al;
20	u_int mask;
21
22	if (family == AF_UNSPEC) {
23		if (strchr(host, ':') != NULL)
24			family = AF_INET6;
25		else
26			family = AF_INET;
27	}
28	if (family != AF_INET && family != AF_INET6)
29		return NULL;
30
31	al = calloc(1, sizeof(*al));
32	if (al == NULL) {
33		fprintf(stderr, "alist_new out of memory\n");
34		return NULL;
35	}
36
37	while (ISSPACE(*host))
38		host++;
39
40	if (*host == '!') {
41		al->al_not = 1;
42		host++;
43		while (ISSPACE(*host))
44			host++;
45	}
46
47	bits = -1;
48	slash = strchr(host, '/');
49	if (slash != NULL) {
50		*slash = '\0';
51		bits = atoi(slash + 1);
52	}
53
54	if (family == AF_INET) {
55		if (bits > 32)
56			goto bad;
57
58		a = b = c = d = -1;
59		sscanf(host, "%d.%d.%d.%d", &a, &b, &c, &d);
60
61		if (bits > 0 && bits < 33) {
62			mask = 0xffffffff << (32 - bits);
63		} else if (b == -1) {
64			mask = 0xff000000;
65			b = c = d = 0;
66		} else if (c == -1) {
67			mask = 0xffff0000;
68			c = d = 0;
69		} else if (d == -1) {
70			mask = 0xffffff00;
71			d = 0;
72		} else {
73			mask = 0xffffffff;
74		}
75		al->al_mask = htonl(mask);
76	} else {
77		if (bits > 128)
78			goto bad;
79		fill6bits(bits, al->al_i6mask.i6);
80	}
81
82	if (gethost(family, host, &al->al_i6addr) == -1) {
83		if (slash != NULL)
84			*slash = '/';
85		fprintf(stderr, "Cannot parse hostname\n");
86		goto bad;
87	}
88	al->al_family = family;
89	if (slash != NULL)
90		*slash = '/';
91	return al;
92bad:
93	free(al);
94	return NULL;
95}
96