Merge from vendor branch OPENSSL:
[dragonfly.git] / contrib / ipfilter / ipft_tx.c
1 /*
2  * Copyright (C) 1995-2001 by Darren Reed.
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  */
6 #if defined(__sgi) && (IRIX > 602)
7 # include <sys/ptimers.h>
8 #endif
9 #include <stdio.h>
10 #include <ctype.h>
11 #include <assert.h>
12 #include <string.h>
13 #include <sys/types.h>
14 #if !defined(__SVR4) && !defined(__svr4__)
15 #include <strings.h>
16 #else
17 #include <sys/byteorder.h>
18 #endif
19 #include <sys/param.h>
20 #include <sys/time.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <stddef.h>
24 #include <sys/socket.h>
25 #include <sys/ioctl.h>
26 #include <netinet/in.h>
27 #include <netinet/in_systm.h>
28 #ifndef linux
29 #include <netinet/ip_var.h>
30 #endif
31 #include <netinet/ip.h>
32 #include <netinet/udp.h>
33 #include <netinet/tcp.h>
34 #include <netinet/ip_icmp.h>
35 #include <arpa/inet.h>
36 #include <net/if.h>
37 #include <netdb.h>
38 #include <arpa/nameser.h>
39 #include <resolv.h>
40 #include "ip_compat.h"
41 #include <netinet/tcpip.h>
42 #include "ipf.h"
43 #include "ipt.h"
44
45 #if !defined(lint)
46 static const char sccsid[] = "@(#)ipft_tx.c     1.7 6/5/96 (C) 1993 Darren Reed";
47 static const char rcsid[] = "@(#)$Id: ipft_tx.c,v 2.3.2.8 2002/12/06 11:40:26 darrenr Exp $";
48 #endif
49
50 extern  int     opts;
51
52 static  char    *tx_proto = "";
53
54 static  int     text_open __P((char *)), text_close __P((void));
55 static  int     text_readip __P((char *, int, char **, int *));
56 static  int     parseline __P((char *, ip_t *, char **, int *));
57
58 static  char    _tcp_flagset[] = "FSRPAUEC";
59 static  u_char  _tcp_flags[] = { TH_FIN, TH_SYN, TH_RST, TH_PUSH,
60                                 TH_ACK, TH_URG, TH_ECN, TH_CWR };
61
62 struct  ipread  iptext = { text_open, text_close, text_readip };
63 static  FILE    *tfp = NULL;
64 static  int     tfd = -1;
65
66 static  u_32_t  tx_hostnum __P((char *, int *));
67 static  u_short tx_portnum __P((char *));
68
69
70 /*
71  * returns an ip address as a long var as a result of either a DNS lookup or
72  * straight inet_addr() call
73  */
74 static  u_32_t  tx_hostnum(host, resolved)
75 char    *host;
76 int     *resolved;
77 {
78         struct  hostent *hp;
79         struct  netent  *np;
80
81         *resolved = 0;
82         if (!strcasecmp("any",host))
83                 return 0L;
84         if (isdigit(*host))
85                 return inet_addr(host);
86
87         if (!(hp = gethostbyname(host))) {
88                 if (!(np = getnetbyname(host))) {
89                         *resolved = -1;
90                         fprintf(stderr, "can't resolve hostname: %s\n", host);
91                         return 0;
92                 }
93                 return htonl(np->n_net);
94         }
95         return *(u_32_t *)hp->h_addr;
96 }
97
98
99 /*
100  * find the port number given by the name, either from getservbyname() or
101  * straight atoi()
102  */
103 static  u_short tx_portnum(name)
104 char    *name;
105 {
106         struct  servent *sp, *sp2;
107         u_short p1 = 0;
108
109         if (isdigit(*name))
110                 return (u_short)atoi(name);
111         if (!tx_proto)
112                 tx_proto = "tcp/udp";
113         if (strcasecmp(tx_proto, "tcp/udp")) {
114                 sp = getservbyname(name, tx_proto);
115                 if (sp)
116                         return ntohs(sp->s_port);
117                 (void) fprintf(stderr, "unknown service \"%s\".\n", name);
118                 return 0;
119         }
120         sp = getservbyname(name, "tcp");
121         if (sp)
122                 p1 = sp->s_port;
123         sp2 = getservbyname(name, "udp");
124         if (!sp || !sp2) {
125                 (void) fprintf(stderr, "unknown tcp/udp service \"%s\".\n",
126                         name);
127                 return 0;
128         }
129         if (p1 != sp2->s_port) {
130                 (void) fprintf(stderr, "%s %d/tcp is a different port to ",
131                         name, p1);
132                 (void) fprintf(stderr, "%s %d/udp\n", name, sp->s_port);
133                 return 0;
134         }
135         return ntohs(p1);
136 }
137
138
139 char    *tx_icmptypes[] = {
140         "echorep", (char *)NULL, (char *)NULL, "unreach", "squench",
141         "redir", (char *)NULL, (char *)NULL, "echo", "routerad",
142         "routersol", "timex", "paramprob", "timest", "timestrep",
143         "inforeq", "inforep", "maskreq", "maskrep", "END"
144 };
145
146 static  int     text_open(fname)
147 char    *fname;
148 {
149         if (tfp && tfd != -1) {
150                 rewind(tfp);
151                 return tfd;
152         }
153
154         if (!strcmp(fname, "-")) {
155                 tfd = 0;
156                 tfp = stdin;
157         } else {
158                 tfd = open(fname, O_RDONLY);
159                 if (tfd != -1)
160                         tfp = fdopen(tfd, "r");
161         }
162         return tfd;
163 }
164
165
166 static  int     text_close()
167 {
168         int     cfd = tfd;
169
170         tfd = -1;
171         return close(cfd);
172 }
173
174
175 static  int     text_readip(buf, cnt, ifn, dir)
176 char    *buf, **ifn;
177 int     cnt, *dir;
178 {
179         register char *s;
180         char    line[513];
181
182         *ifn = NULL;
183         while (fgets(line, sizeof(line)-1, tfp)) {
184                 if ((s = index(line, '\n')))
185                         *s = '\0';
186                 if ((s = index(line, '\r')))
187                         *s = '\0';
188                 if ((s = index(line, '#')))
189                         *s = '\0';
190                 if (!*line)
191                         continue;
192                 if (!(opts & OPT_BRIEF))
193                         printf("input: %s\n", line);
194                 *ifn = NULL;
195                 *dir = 0;
196                 if (!parseline(line, (ip_t *)buf, ifn, dir))
197 #if 0
198                         return sizeof(ip_t) + sizeof(tcphdr_t);
199 #else
200                         return sizeof(ip_t);
201 #endif
202         }
203         return -1;
204 }
205
206 static  int     parseline(line, ip, ifn, out)
207 char    *line;
208 ip_t    *ip;
209 char    **ifn;
210 int     *out;
211 {
212         tcphdr_t        th, *tcp = &th;
213         struct  icmp    icmp, *ic = &icmp;
214         char    *cps[20], **cpp, c, ipopts[68];
215         int     i, r;
216
217         if (*ifn)
218                 free(*ifn);
219         bzero((char *)ip, MAX(sizeof(*tcp), sizeof(*ic)) + sizeof(*ip));
220         bzero((char *)tcp, sizeof(*tcp));
221         bzero((char *)ic, sizeof(*ic));
222         bzero(ipopts, sizeof(ipopts));
223         ip->ip_hl = sizeof(*ip) >> 2;
224         ip->ip_v = IPVERSION;
225         for (i = 0, cps[0] = strtok(line, " \b\t\r\n"); cps[i] && (i < 19); )
226                 cps[++i] = strtok(NULL, " \b\t\r\n");
227
228         cpp = cps;
229         if (!*cpp)
230                 return 1;
231
232         c = **cpp;
233         if (!isalpha(c) || (tolower(c) != 'o' && tolower(c) != 'i')) {
234                 fprintf(stderr, "bad direction \"%s\"\n", *cpp);
235                 return 1;
236         }
237         *out = (tolower(c) == 'o') ? 1 : 0;
238         cpp++;
239         if (!*cpp)
240                 return 1;
241
242         if (!strcasecmp(*cpp, "on")) {
243                 cpp++;
244                 if (!*cpp)
245                         return 1;
246                 *ifn = strdup(*cpp++);
247                 if (!*cpp)
248                         return 1;
249         }
250
251         c = **cpp;
252         ip->ip_len = sizeof(ip_t);
253         if (!strcasecmp(*cpp, "tcp") || !strcasecmp(*cpp, "udp") ||
254             !strcasecmp(*cpp, "icmp")) {
255                 if (c == 't') {
256                         ip->ip_p = IPPROTO_TCP;
257                         ip->ip_len += sizeof(struct tcphdr);
258                         tx_proto = "tcp";
259                 } else if (c == 'u') {
260                         ip->ip_p = IPPROTO_UDP;
261                         ip->ip_len += sizeof(struct udphdr);
262                         tx_proto = "udp";
263                 } else {
264                         ip->ip_p = IPPROTO_ICMP;
265                         ip->ip_len += ICMPERR_IPICMPHLEN;
266                         tx_proto = "icmp";
267                 }
268                 cpp++;
269         } else if (isdigit(**cpp) && !index(*cpp, '.')) {
270                 ip->ip_p = atoi(*cpp);
271                 cpp++;
272         } else
273                 ip->ip_p = IPPROTO_IP;
274
275         if (!*cpp)
276                 return 1;
277         if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) {
278                 char    *last;
279
280                 last = index(*cpp, ',');
281                 if (!last) {
282                         fprintf(stderr, "tcp/udp with no source port\n");
283                         return 1;
284                 }
285                 *last++ = '\0';
286                 tcp->th_sport = htons(tx_portnum(last));
287         }
288         ip->ip_src.s_addr = tx_hostnum(*cpp, &r);
289         cpp++;
290         if (!*cpp)
291                 return 1;
292
293         if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) {
294                 char    *last;
295
296                 last = index(*cpp, ',');
297                 if (!last) {
298                         fprintf(stderr, "tcp/udp with no destination port\n");
299                         return 1;
300                 }
301                 *last++ = '\0';
302                 tcp->th_dport = htons(tx_portnum(last));
303         }
304         ip->ip_dst.s_addr = tx_hostnum(*cpp, &r);
305         cpp++;
306         if (*cpp && ip->ip_p == IPPROTO_TCP) {
307                 extern  char    _tcp_flagset[];
308                 extern  u_char  _tcp_flags[];
309                 char    *s, *t;
310
311                 for (s = *cpp; *s; s++)
312                         if ((t  = index(_tcp_flagset, *s)))
313                                 tcp->th_flags |= _tcp_flags[t - _tcp_flagset];
314                 if (tcp->th_flags)
315                         cpp++;
316                 assert(tcp->th_flags != 0);
317                 tcp->th_win = htons(4096);
318                 tcp->th_off = sizeof(*tcp) >> 2;
319         } else if (*cpp && ip->ip_p == IPPROTO_ICMP) {
320                 extern  char    *tx_icmptypes[];
321                 char    **s, *t;
322                 int     i;
323
324                 for (s = tx_icmptypes, i = 0; !*s || strcmp(*s, "END");
325                      s++, i++)
326                         if (*s && !strncasecmp(*cpp, *s, strlen(*s))) {
327                                 ic->icmp_type = i;
328                                 if ((t = index(*cpp, ',')))
329                                         ic->icmp_code = atoi(t+1);
330                                 cpp++;
331                                 break;
332                         }
333         }
334
335         if (*cpp && !strcasecmp(*cpp, "opt")) {
336                 u_long  olen;
337
338                 cpp++;
339                 olen = buildopts(*cpp, ipopts, (ip->ip_hl - 5) << 2);
340                 if (olen) {
341                         bcopy(ipopts, (char *)(ip + 1), olen);
342                         ip->ip_hl += olen >> 2;
343                 }
344         }
345         if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP)
346                 bcopy((char *)tcp, ((char *)ip) + (ip->ip_hl << 2),
347                         sizeof(*tcp));
348         else if (ip->ip_p == IPPROTO_ICMP)
349                 bcopy((char *)ic, ((char *)ip) + (ip->ip_hl << 2),
350                         sizeof(*ic));
351         ip->ip_len = htons(ip->ip_len);
352         return 0;
353 }