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