1 /*
2 * foobar.c
3 * (C)1998-2011 by Marc Huber <Marc.Huber@web.de>
4 * All rights reserved.
5 *
6 * RFC 1639 (FTP Operation Over Big Address Records)
7 * RFC 2428 (FTP Extensions for IPv6 and NATs)
8 * RFC 959 (FTP)
9 * RFC 1700 (Assigned Numbers)
10 *
11 * $Id: foobar.c,v 1.15 2015/03/14 06:11:24 marc Exp marc $
12 *
13 */
14
15 #include "headers.h"
16
17 static const char rcsid[] __attribute__ ((used)) = "$Id: foobar.c,v 1.15 2015/03/14 06:11:24 marc Exp marc $";
18
19 #define FOOBAR_AF_IP 4 /* IP (IPv4) */
20 #define FOOBAR_AF_ST 5 /* ST Datagram Mode */
21 #define FOOBAR_AF_SIP 6 /* SIP (IPv6) */
22 #define FOOBAR_AF_TPIX 7 /* TP/IX */
23 #define FOOBAR_AF_PIP 8 /* PIP */
24 #define FOOBAR_AF_TUBA 9 /* TUBA */
25 #define FOOBAR_AF_IPX 16 /* Novell IPX */
26
27 #define RFC2428_AF_IP 1 /* IP (IP version 4) */
28 #define RFC2428_AF_IP6 2 /* IP6 (IP version 6) */
29
30 struct foobar_af_mapping_s {
31 int foobar_af;
32 int af;
33 };
34
35 struct foobar_af_mapping_s foobar_af_mapping[] = {
36 #ifdef AF_INET
37 {FOOBAR_AF_IP, AF_INET,},
38 #endif
39 #ifdef AF_INET6
40 {FOOBAR_AF_SIP, AF_INET6,},
41 #endif
42 {-1, -1,},
43 };
44
45 struct rfc2428_af_mapping_s {
46 int rfc2428_af;
47 int af;
48 };
49
50 struct rfc2428_af_mapping_s rfc2428_af_mapping[] = {
51 #ifdef AF_INET
52 {RFC2428_AF_IP, AF_INET,},
53 #endif
54 #ifdef AF_INET6
55 {RFC2428_AF_IP6, AF_INET6,},
56 #endif
57 {-1, -1,},
58 };
59
foobar2af(int af)60 int foobar2af(int af)
61 {
62 struct foobar_af_mapping_s *m = foobar_af_mapping;
63 for (; m->foobar_af != -1; m++)
64 if (m->foobar_af == af)
65 return m->af;
66 return -1;
67 }
68
af2foobar(int af)69 int af2foobar(int af)
70 {
71 struct foobar_af_mapping_s *m = foobar_af_mapping;
72 for (; m->foobar_af != -1; m++)
73 if (m->af == af)
74 return m->foobar_af;
75 return -1;
76 }
77
rfc2428_2_af(int af)78 int rfc2428_2_af(int af)
79 {
80 struct rfc2428_af_mapping_s *m = rfc2428_af_mapping;
81
82 for (; m->rfc2428_af != -1; m++)
83 if (m->rfc2428_af == af)
84 return m->af;
85 return -1;
86 }
87
print_rfc2428_families(char * s,size_t len)88 char *print_rfc2428_families(char *s, size_t len)
89 {
90 char *t = s;
91 struct rfc2428_af_mapping_s *m = rfc2428_af_mapping;
92
93 for (; m->rfc2428_af != -1; m++) {
94 if (s != t)
95 *t++ = ',';
96 t += snprintf(t, (size_t) (s + len - t), "%d", m->rfc2428_af);
97 }
98 return s;
99 }
100
print_foobar_families(char * s,size_t len)101 char *print_foobar_families(char *s, size_t len)
102 {
103 char *t = s;
104 struct foobar_af_mapping_s *m = foobar_af_mapping;
105
106 for (; m->foobar_af != -1; m++) {
107 if (s != t)
108 *t++ = ',';
109 t += snprintf(t, (size_t) (s + len - t), "%d", m->foobar_af);
110 }
111 return s;
112 }
113
af2rfc2428(int af)114 int af2rfc2428(int af)
115 {
116 struct rfc2428_af_mapping_s *m = rfc2428_af_mapping;
117 for (; m->rfc2428_af != -1; m++)
118 if (m->af == af)
119 return m->rfc2428_af;
120 return -1;
121 }
122
123 /* foobar_eval() -- evaluate <long-host-port> */
124 /* returns foobar address family, -1 on error */
125 /* char *long-host-port, void *addr, int *addrlen, void *port, int *portlen */
foobar_eval(sockaddr_union * sa,char * s)126 int foobar_eval(sockaddr_union * sa, char *s)
127 {
128 u_char arr[513];
129 int length = 0;
130
131 DebugIn(DEBUG_COMMAND);
132
133 if (!s) {
134 Debug((DEBUG_COMMAND, "- %s: arg == NULL\n", __func__));
135 return -1;
136 }
137
138 memset(arr, 0, (size_t) 513);
139
140 while (*s && isspace((int) *s))
141 s++;
142
143 for (; *s && !isspace((int) *s) && length < 512; s++)
144 if (isdigit((int) *s)) {
145 arr[length] *= 10;
146 arr[length] += (u_char) * s - '0';
147 } else if (*s == ',')
148 length++;
149 else {
150 Debug((DEBUG_COMMAND, "- %s: invalid char\n", __func__));
151 return -1;
152 }
153
154 if (++length != arr[1] + 3 + arr[arr[1] + 2]) {
155 Debug((DEBUG_COMMAND, "- %s: consistency check failed\n", __func__));
156 return -1;
157 }
158
159 memset(sa, 0, sizeof(sockaddr_union));
160 sa->sa.sa_family = foobar2af(arr[1]);
161
162 switch (sa->sa.sa_family) {
163 #ifdef AF_INET
164 case AF_INET:
165 memcpy(&sa->sin.sin_addr, arr + 2, (size_t) 4);
166 memcpy(&sa->sin.sin_port, arr + arr[1] + 3, (size_t) 2);
167 return sa->sa.sa_family;
168 #endif /* AF_INET */
169 #ifdef AF_INET6
170 case AF_INET6:
171 memcpy(&sa->sin6.sin6_addr, arr + 2, (size_t) 16);
172 memcpy(&sa->sin6.sin6_port, arr + arr[1] + 3, (size_t) 2);
173 return sa->sa.sa_family;
174 #endif /* AF_INET6 */
175 }
176
177 Debug((DEBUG_COMMAND, "- %s: af = %d\n", __func__, arr[0]));
178 return -2;
179 }
180
foobar_str(sockaddr_union * sa,char * res,size_t reslen)181 char *foobar_str(sockaddr_union * sa, char *res, size_t reslen)
182 {
183 char *s = res;
184 int al, pl;
185 u_char *a, *p;
186
187 switch (sa->sa.sa_family) {
188 #ifdef AF_INET
189 case AF_INET:
190 al = 4, pl = 2;
191 a = (u_char *) & sa->sin.sin_addr;
192 p = (u_char *) & sa->sin.sin_port;
193 break;
194 #endif
195 #ifdef AF_INET6
196 case AF_INET6:
197 al = 16, pl = 2;
198 a = (u_char *) & sa->sin6.sin6_addr;
199 p = (u_char *) & sa->sin6.sin6_port;
200 break;
201 #endif
202 default:
203 return "(NULL)";
204 }
205
206 s += snprintf(s, (size_t) (res + reslen - s), "%d,%u", af2foobar(sa->sa.sa_family), (u_int) al);
207
208 while (al--)
209 s += snprintf(s, (size_t) (res + reslen - s), ",%u", (u_int) * a++);
210
211 s += snprintf(s, (size_t) (res + reslen - s), ",%u", (u_int) pl);
212
213 while (pl--)
214 s += snprintf(s, (size_t) (res + reslen - s), ",%u", (u_int) * p++);
215
216 return res;
217 }
218
rfc2428_eval(sockaddr_union * sa,char * in)219 int rfc2428_eval(sockaddr_union * sa, char *in)
220 {
221 char *s = alloca(strlen(in) + 1);
222 char delimiter;
223 int proto = -1;
224 char *net_prt = NULL;
225 char *net_addr = NULL;
226 char *tcp_port = NULL;
227 char *remainder = NULL;
228 int af;
229
230 DebugIn(DEBUG_COMMAND);
231
232 strcpy(s, in);
233
234 if (!s) {
235 Debug((DEBUG_COMMAND, "- %s: arg == NULL\n", __func__));
236 return -1;
237 }
238
239 delimiter = s[0];
240 net_prt = s + 1;
241 if ((net_addr = strchr(net_prt, delimiter))) {
242 *net_addr++ = 0;
243 if ((tcp_port = strchr(net_addr, delimiter))) {
244 *tcp_port++ = 0;
245
246 if ((remainder = strchr(tcp_port, delimiter)))
247 *remainder = 0;
248 }
249 }
250
251 if (!remainder) {
252 Debug((DEBUG_COMMAND, "- %s: parse error\n", __func__));
253 return -1;
254 }
255
256 proto = atoi(net_prt);
257
258 af = rfc2428_2_af(proto);
259 if (af < 0) {
260 Debug((DEBUG_COMMAND, "- %s: unknown protocol\n", __func__));
261 return -2;
262 }
263
264 if (!tcp_port || su_pton_p(sa, net_addr, atoi(tcp_port)) || af != sa->sa.sa_family) {
265 Debug((DEBUG_COMMAND, "- %s: error\n", __func__));
266 return -1;
267 }
268
269 Debug((DEBUG_COMMAND, "- %s: af = %d\n", __func__, proto));
270 return sa->sa.sa_family;
271 }
272
rfc959_eval(sockaddr_union * sa,char * s)273 int rfc959_eval(sockaddr_union * sa, char *s)
274 {
275 u_char arr[6];
276 int length = 0;
277
278 DebugIn(DEBUG_COMMAND);
279
280 if (!s) {
281 Debug((DEBUG_COMMAND, "- %s: arg == NULL\n", __func__));
282 return -1;
283 }
284
285 memset(arr, 0, (size_t) 6);
286
287 while (*s && isspace((int) *s))
288 s++;
289
290 for (; *s && !isspace((int) *s) && length < 6; s++)
291 if (isdigit((int) *s)) {
292 arr[length] *= 10;
293 arr[length] += (u_char) * s - '0';
294 } else if (*s == ',')
295 length++;
296 else {
297 Debug((DEBUG_COMMAND, "- %s: invalid char\n", __func__));
298 return -1;
299 }
300
301 if (length != 5) {
302 Debug((DEBUG_COMMAND, "- %s: consistency check failed\n", __func__));
303 return -1;
304 }
305
306 memset(sa, 0, sizeof(sockaddr_union));
307 sa->sa.sa_family = AF_INET;
308 memcpy(&sa->sin.sin_addr, arr, (size_t) 4);
309 memcpy(&sa->sin.sin_port, arr + 4, (size_t) 2);
310
311 Debug((DEBUG_COMMAND, "- %s: af = AF_INET\n", __func__));
312 return AF_INET;
313 }
314
rfc959_str(sockaddr_union * sa,char * res,size_t reslen)315 char *rfc959_str(sockaddr_union * sa, char *res, size_t reslen)
316 {
317 char *s = res;
318 int al = 4, pl = 2;
319 u_char *a = NULL, *p = NULL;
320 switch (sa->sa.sa_family) {
321 #ifdef AF_INET
322 case AF_INET:
323 a = (u_char *) & sa->sin.sin_addr;
324 p = (u_char *) & sa->sin.sin_port;
325 break;
326 #endif /* AF_INET */
327 #ifdef AF_INET6
328 case AF_INET6:
329 a = (u_char *) & sa->sin6.sin6_addr + 12;
330 p = (u_char *) & sa->sin6.sin6_port;
331 break;
332 #endif /* AF_INET6 */
333 default:
334 return "";
335 }
336
337 for (; al; a++, al--) {
338 if (al != 4)
339 *s++ = ',';
340 s += snprintf(s, (size_t) (res + reslen - s), "%u", (u_int) * a);
341 }
342
343 for (; pl; p++, pl--)
344 s += snprintf(s, (size_t) (res + reslen - s), ",%u", (u_int) * p);
345
346 return res;
347 }
348
rfc2428_str(sockaddr_union * sa,char * res,size_t reslen)349 char *rfc2428_str(sockaddr_union * sa, char *res, size_t reslen)
350 {
351 char buf[INET6_ADDRSTRLEN];
352 char *s = res;
353 char delimiter = '|';
354 u_short p;
355
356 *s++ = delimiter;
357
358 switch (sa->sa.sa_family) {
359 #ifdef AF_INET
360 case AF_INET:
361 *s++ = RFC2428_AF_IP + '0';
362 p = sa->sin.sin_port;
363 break;
364 #endif
365 #ifdef AF_INET6
366 case AF_INET6:
367 *s++ = RFC2428_AF_IP6 + '0';
368 p = sa->sin6.sin6_port;
369 break;
370 #endif
371 default:
372 return "(NULL)";
373 }
374
375 snprintf(s, (size_t) (res + reslen - s - 1), "%c%s%c%d%c", delimiter, su_ntop(sa, buf, (socklen_t) sizeof(buf)), delimiter, ntohs(p), delimiter);
376
377 return res;
378 }
379