Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <ctype.h>
4
#include <ip.h>
5
 
6
char*
7
v4parseip(uchar *to, char *from)
8
{
9
	int i;
10
	char *p;
11
 
12
	p = from;
13
	for(i = 0; i < 4 && *p; i++){
14
		to[i] = strtoul(p, &p, 0);
15
		if(*p == '.')
16
			p++;
17
	}
18
	switch(CLASS(to)){
19
	case 0:	/* class A - 1 uchar net */
20
	case 1:
21
		if(i == 3){
22
			to[3] = to[2];
23
			to[2] = to[1];
24
			to[1] = 0;
25
		} else if (i == 2){
26
			to[3] = to[1];
27
			to[1] = 0;
28
		}
29
		break;
30
	case 2:	/* class B - 2 uchar net */
31
		if(i == 3){
32
			to[3] = to[2];
33
			to[2] = 0;
34
		}
35
		break;
36
	}
37
	return p;
38
}
39
 
40
static int
41
ipcharok(int c)
42
{
43
	return c == '.' || c == ':' || isascii(c) && isxdigit(c);
44
}
45
 
46
static int
47
delimchar(int c)
48
{
49
	if(c == '\0')
50
		return 1;
51
	if(c == '.' || c == ':' || isascii(c) && isalnum(c))
52
		return 0;
53
	return 1;
54
}
55
 
56
/*
57
 * `from' may contain an address followed by other characters,
58
 * at least in /boot, so we permit whitespace (and more) after the address.
59
 * we do ensure that "delete" cannot be parsed as "de::".
60
 *
61
 * some callers don't check the return value for errors, so
62
 * set `to' to something distinctive in the case of a parse error.
63
 */
64
vlong
65
parseip(uchar *to, char *from)
66
{
67
	int i, elipsis = 0, v4 = 1;
68
	ulong x;
69
	char *p, *op;
70
 
71
	memset(to, 0, IPaddrlen);
72
	p = from;
73
	for(i = 0; i < IPaddrlen && ipcharok(*p); i+=2){
74
		op = p;
75
		x = strtoul(p, &p, 16);
76
		if((*p == '.' && i <= IPaddrlen-4) || (*p == 0 && i == 0)){
77
			/* ends with v4 */
78
			p = v4parseip(to+i, op);
79
			i += 4;
80
			break;
81
		}
82
		/* v6: at most 4 hex digits, followed by colon or delim */
83
		if(x != (ushort)x || *p != ':' && !delimchar(*p)) {
84
			memset(to, 0, IPaddrlen);
85
			return -1;			/* parse error */
86
		}
87
		to[i] = x>>8;
88
		to[i+1] = x;
89
		if(*p == ':'){
90
			v4 = 0;
91
			if(*++p == ':'){	/* :: is elided zero short(s) */
92
				if (elipsis) {
93
					memset(to, 0, IPaddrlen);
94
					return -1;	/* second :: */
95
				}
96
				elipsis = i+2;
97
				p++;
98
			}
99
		} else if (p == op)		/* strtoul made no progress? */
100
			break;
101
	}
102
	if (p == from || !delimchar(*p)) {
103
		memset(to, 0, IPaddrlen);
104
		return -1;				/* parse error */
105
	}
106
	if(i < IPaddrlen){
107
		memmove(&to[elipsis+IPaddrlen-i], &to[elipsis], i-elipsis);
108
		memset(&to[elipsis], 0, IPaddrlen-i);
109
	}
110
	if(v4){
111
		to[10] = to[11] = 0xff;
112
		return nhgetl(to + IPv4off);
113
	} else
114
		return 6;
115
}
116
 
117
/*
118
 *  hack to allow ip v4 masks to be entered in the old
119
 *  style
120
 */
121
vlong
122
parseipmask(uchar *to, char *from)
123
{
124
	int i, w;
125
	vlong x;
126
	uchar *p;
127
 
128
	if(*from == '/'){
129
		/* as a number of prefix bits */
130
		i = atoi(from+1);
131
		if(i < 0)
132
			i = 0;
133
		if(i > 128)
134
			i = 128;
135
		w = i;
136
		memset(to, 0, IPaddrlen);
137
		for(p = to; i >= 8; i -= 8)
138
			*p++ = 0xff;
139
		if(i > 0)
140
			*p = ~((1<<(8-i))-1);
141
		x = nhgetl(to+IPv4off);
142
		/*
143
		 * identify as ipv6 if the mask is inexpressible as a v4 mask
144
		 * (because it has too few mask bits).  Arguably, we could
145
		 * always return 6 here.
146
		 */
147
		if (w < 8*(IPaddrlen-IPv4addrlen))
148
			return 6;
149
	} else {
150
		/* as a straight v4 bit mask */
151
		x = parseip(to, from);
152
		if (x != -1)
153
			x = (ulong)nhgetl(to + IPv4off);
154
		if(memcmp(to, v4prefix, IPv4off) == 0)
155
			memset(to, 0xff, IPv4off);
156
	}
157
	return x;
158
}
159
 
160
/*
161
 *  parse a v4 ip address/mask in cidr format
162
 */
163
char*
164
v4parsecidr(uchar *addr, uchar *mask, char *from)
165
{
166
	int i;
167
	char *p;
168
	uchar *a;
169
 
170
	p = v4parseip(addr, from);
171
 
172
	if(*p == '/'){
173
		/* as a number of prefix bits */
174
		i = strtoul(p+1, &p, 0);
175
		if(i > 32)
176
			i = 32;
177
		memset(mask, 0, IPv4addrlen);
178
		for(a = mask; i >= 8; i -= 8)
179
			*a++ = 0xff;
180
		if(i > 0)
181
			*a = ~((1<<(8-i))-1);
182
	} else 
183
		memcpy(mask, defmask(addr), IPv4addrlen);
184
	return p;
185
}