1 /* these functions are useful for dealing with IPv4 */
2 #ifndef __ip4_h
3 #define __ip4_h
4 
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <sys/param.h>
8 #include <netinet/in.h>
9 #include <arpa/inet.h>
10 #include <sys/types.h>
11 #include <fcntl.h>
12 
13 #include "str.h"
14 #include "mem.h"
15 
16 #ifndef IP_LEN
17 #define IP_LEN	4
18 #endif
19 
ipv4_null(unsigned char * ip)20 static int inline ipv4_null(unsigned char *ip)
21 {
22 	int i;
23 	for (i = 0; ip[i] == 0 && i < 4; i++);
24 	return i == 4 ? 1 : 0;
25 }
ipv4_scan(const char * str,unsigned char ip[4])26 static int inline ipv4_scan(const char *str, unsigned char ip[4])
27 {
28 	int p, v;
29 
30 	ip[0] = ip[1] = ip[2] = ip[3] = 0;
31 	for (p = v = 0; *str && p < 4;) {
32 		switch (*str) {
33 		case '0': v *= 10; break;
34 		case '1': v *= 10; v ++; break;
35 		case '2': v *= 10; v += 2; break;
36 		case '3': v *= 10; v += 3; break;
37 		case '4': v *= 10; v += 4; break;
38 		case '5': v *= 10; v += 5; break;
39 		case '6': v *= 10; v += 6; break;
40 		case '7': v *= 10; v += 7; break;
41 		case '8': v *= 10; v += 8; break;
42 		case '9': v *= 10; v += 9; break;
43 		case '.': ip[p] = v; v = 0; p++; break;
44 		default: return 0;
45 		};
46 		str++;
47 	}
48 	if (p == 4) return 0;
49 	ip[p] = v;
50 	return 4;
51 }
ipv4_in_subnet(unsigned char cidr[8],unsigned char ip[4])52 static int inline ipv4_in_subnet(unsigned char cidr[8], unsigned char ip[4])
53 {
54 	register int i;
55 	if (ipv4_null(cidr)) return 1;
56 	for (i = 0; i < 4; i++) {
57 		if (cidr[i] != (ip[i] & cidr[4+i]))
58 			return 0;
59 	}
60 	return 1;
61 }
ipv4_cidr(char * str,unsigned char cidr[8])62 static int inline ipv4_cidr(char *str, unsigned char cidr[8])
63 {
64 	int r;
65 	str_t s;
66 	char *p;
67 
68 	/* like ipv4_scan but parses a CIDR number */
69 	str_init(s);
70 	str_copy(s, str);
71 	for (p = str(s); *p && *p != '/'; p++);
72 	if (*p == '/') {
73 		*p = 0; p++;
74 		if (!ipv4_scan(str(s), cidr)) {
75 			mem_free(str(s));
76 			return 0;
77 		}
78 		for (r = 0; p[r]; r++)
79 			if (p[r] == '.' && ipv4_scan(p, cidr+4)) {
80 				/* form of IN/IN */
81 				mem_free(str(s));
82 				return 8;
83 			}
84 		/* must be in cidr notation (really) */
85 		r = atoi(p);
86 		if (r == -1) {
87 			mem_free(str(s));
88 			return 0;
89 		}
90 		cidr[4] = cidr[5] = cidr[6] = cidr[7] = 0xFF;
91 		if (r < 8) {
92 			cidr[4] = (0xFF << (8 - r));
93 			cidr[5] = cidr[6] = cidr[7] = 0x00;
94 		} else if (r < 16) {
95 			cidr[5] = (0xFF << (16 - r));
96 			cidr[6] = cidr[7] = 0x00;
97 		} else if (r < 24) {
98 			cidr[6] = (0xFF << (24 - r));
99 			cidr[7] = 0x00;
100 		} else {
101 			cidr[7] = (0xFF << (32 - r));
102 		}
103 		mem_free(str(s));
104 		return 8;
105 	} else {
106 		mem_free(str(s));
107 		return 0;
108 	}
109 }
socket_bind4(int fd,unsigned char ip[4],int port)110 static int inline socket_bind4(int fd, unsigned char ip[4], int port)
111 {
112 	struct sockaddr_in sin;
113 
114 	memzero(&sin, sizeof(sin));
115 
116 	sin.sin_family = PF_INET;
117 	/* Clib */
118 	sin.sin_port = htons(port);
119 	memcpy(&sin.sin_addr, ip, 4);
120 
121 	return bind(fd, (struct sockaddr *)&sin, sizeof(sin));
122 }
socket_bind4_reuse(int fd,unsigned char ip[4],int port)123 static int inline socket_bind4_reuse(int fd, unsigned char ip[4], int port)
124 {
125 	int opt = 1;
126 	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
127 	return socket_bind4(fd, ip, port);
128 }
socket_peer4(int fd,unsigned char ip[4],int * port)129 static int inline socket_peer4(int fd, unsigned char ip[4], int *port)
130 {
131 	struct sockaddr_in sin;
132 	int silen;
133 
134 	memzero(&sin, sizeof(sin));
135 
136 	silen = sizeof(sin);
137 	sin.sin_family = PF_INET;
138 	if (getpeername(fd, (struct sockaddr *)&sin, (int *)&silen) == -1) {
139 		return 0;
140 	}
141 
142 	if (sin.sin_family != PF_INET)
143 		return 0;
144 
145 	memcpy(ip, &sin.sin_addr, 4);
146 	*port = ntohs(sin.sin_port);
147 	return 1;
148 }
socket_local4(int fd,unsigned char ip[4],int * port)149 static int inline socket_local4(int fd, unsigned char ip[4], int *port)
150 {
151 	struct sockaddr_in sin;
152 	int silen;
153 
154 	memzero(&sin, sizeof(sin));
155 
156 	silen = sizeof(sin);
157 	sin.sin_family = PF_INET;
158 	if (getsockname(fd, (struct sockaddr *)&sin, (int *)&silen) == -1) {
159 		return 0;
160 	}
161 
162 	if (sin.sin_family != PF_INET)
163 		return 0;
164 
165 	memcpy(ip, &sin.sin_addr, 4);
166 	*port = ntohs(sin.sin_port);
167 	return 1;
168 }
169 
socket_tcp4(void)170 static int inline socket_tcp4(void)
171 {
172 	int fd;
173 
174 	fd = socket(PF_INET, SOCK_STREAM, 0);
175 	if (fd == -1) return -1;
176 	if (ndelay_on(fd) == -1) { close(fd); return -1; }
177 	return fd;
178 }
socket_udp4(void)179 static int inline socket_udp4(void)
180 {
181 	int fd;
182 
183 	fd = socket(PF_INET, SOCK_DGRAM, 0);
184 	if (fd == -1) return -1;
185 	if (ndelay_on(fd) == -1) { close(fd); return -1; }
186 	return fd;
187 }
socket_accept4(int s,unsigned char ip[4],int * port)188 static int inline socket_accept4(int s, unsigned char ip[4], int *port)
189 {
190 	struct sockaddr_in sa;
191 	int dummy = sizeof sa;
192 	int r;
193 
194 	memzero(&sa, sizeof(sa));
195 
196 	r = accept(s, (struct sockaddr *)&sa, &dummy);
197 	if (r == -1) return -1;
198 
199 	memcpy(ip, &sa.sin_addr, 4);
200 	*port = ntohs(sa.sin_port);
201 
202 	return r;
203 }
socket_recv4(int s,char * buf,int len,unsigned char ip[4],int * port)204 static int inline socket_recv4(int s, char *buf, int len, unsigned char ip[4], int *port)
205 {
206 	struct sockaddr_in sa;
207 	int dummy = sizeof sa;
208 	int r;
209 
210 	memzero(&sa, sizeof(sa));
211 
212 	r = recvfrom(s, buf, len, 0, (struct sockaddr *)&sa, &dummy);
213 	if (r == -1) return -1;
214 
215 	memcpy(ip, &sa.sin_addr, 4);
216 	*port = ntohs(sa.sin_port);
217 
218 	return r;
219 }
socket_send4(int s,const char * buf,int len,const unsigned char ip[4],int port)220 static int inline socket_send4(int s, const char *buf, int len, const unsigned char ip[4], int port)
221 {
222 	struct sockaddr_in sa;
223 
224 	memzero(&sa, sizeof(sa));
225 
226 	sa.sin_family = PF_INET;
227 	sa.sin_port = htons(port);
228 	memcpy(&sa.sin_addr, ip, 4);
229 
230 	return sendto(s, buf, len, 0, (struct sockaddr *)&sa, sizeof(sa));
231 }
232 
233 #endif
234