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