17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * Copyright (C) 1995-2001 by Darren Reed.
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * See the IPFILTER.LICENCE file for details on licencing.
57c478bd9Sstevel@tonic-gate *
6*9b4c7145Sjojemann * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
7*9b4c7145Sjojemann * Use is subject to license terms.
87c478bd9Sstevel@tonic-gate */
9*9b4c7145Sjojemann
10*9b4c7145Sjojemann #pragma ident "%Z%%M% %I% %E% SMI"
11*9b4c7145Sjojemann
127c478bd9Sstevel@tonic-gate #if !defined(lint)
137c478bd9Sstevel@tonic-gate static const char sccsid[] = "@(#)ipft_tx.c 1.7 6/5/96 (C) 1993 Darren Reed";
14ab25eeb5Syz155240 static const char rcsid[] = "@(#)$Id: ipft_tx.c,v 1.15.2.3 2005/06/18 02:41:34 darrenr Exp $";
157c478bd9Sstevel@tonic-gate #endif
167c478bd9Sstevel@tonic-gate
177c478bd9Sstevel@tonic-gate #include <ctype.h>
187c478bd9Sstevel@tonic-gate
197c478bd9Sstevel@tonic-gate #include "ipf.h"
207c478bd9Sstevel@tonic-gate #include "ipt.h"
217c478bd9Sstevel@tonic-gate
22ab25eeb5Syz155240 #ifndef linux
237c478bd9Sstevel@tonic-gate #include <netinet/ip_var.h>
24ab25eeb5Syz155240 #endif
257c478bd9Sstevel@tonic-gate #include <netinet/tcpip.h>
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate extern int opts;
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate static char *tx_proto = "";
317c478bd9Sstevel@tonic-gate
327c478bd9Sstevel@tonic-gate static int text_open __P((char *)), text_close __P((void));
337c478bd9Sstevel@tonic-gate static int text_readip __P((char *, int, char **, int *));
347c478bd9Sstevel@tonic-gate static int parseline __P((char *, ip_t *, char **, int *));
357c478bd9Sstevel@tonic-gate
36ab25eeb5Syz155240 static char myflagset[] = "FSRPAUEC";
37ab25eeb5Syz155240 static u_char myflags[] = { TH_FIN, TH_SYN, TH_RST, TH_PUSH,
387c478bd9Sstevel@tonic-gate TH_ACK, TH_URG, TH_ECN, TH_CWR };
397c478bd9Sstevel@tonic-gate
407c478bd9Sstevel@tonic-gate struct ipread iptext = { text_open, text_close, text_readip, R_DO_CKSUM };
417c478bd9Sstevel@tonic-gate static FILE *tfp = NULL;
427c478bd9Sstevel@tonic-gate static int tfd = -1;
437c478bd9Sstevel@tonic-gate
447c478bd9Sstevel@tonic-gate static u_32_t tx_hostnum __P((char *, int *));
457c478bd9Sstevel@tonic-gate static u_short tx_portnum __P((char *));
467c478bd9Sstevel@tonic-gate
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate /*
497c478bd9Sstevel@tonic-gate * returns an ip address as a long var as a result of either a DNS lookup or
507c478bd9Sstevel@tonic-gate * straight inet_addr() call
517c478bd9Sstevel@tonic-gate */
tx_hostnum(host,resolved)527c478bd9Sstevel@tonic-gate static u_32_t tx_hostnum(host, resolved)
537c478bd9Sstevel@tonic-gate char *host;
547c478bd9Sstevel@tonic-gate int *resolved;
557c478bd9Sstevel@tonic-gate {
56*9b4c7145Sjojemann i6addr_t ipa;
577c478bd9Sstevel@tonic-gate
587c478bd9Sstevel@tonic-gate *resolved = 0;
597c478bd9Sstevel@tonic-gate if (!strcasecmp("any", host))
607c478bd9Sstevel@tonic-gate return 0L;
61ab25eeb5Syz155240 if (ISDIGIT(*host))
627c478bd9Sstevel@tonic-gate return inet_addr(host);
637c478bd9Sstevel@tonic-gate
64*9b4c7145Sjojemann if (gethost(host, &ipa, 0) == -1) {
657c478bd9Sstevel@tonic-gate *resolved = -1;
667c478bd9Sstevel@tonic-gate fprintf(stderr, "can't resolve hostname: %s\n", host);
677c478bd9Sstevel@tonic-gate return 0;
687c478bd9Sstevel@tonic-gate }
69*9b4c7145Sjojemann return ipa.in4_addr;
707c478bd9Sstevel@tonic-gate }
717c478bd9Sstevel@tonic-gate
727c478bd9Sstevel@tonic-gate
737c478bd9Sstevel@tonic-gate /*
747c478bd9Sstevel@tonic-gate * find the port number given by the name, either from getservbyname() or
757c478bd9Sstevel@tonic-gate * straight atoi()
767c478bd9Sstevel@tonic-gate */
tx_portnum(name)777c478bd9Sstevel@tonic-gate static u_short tx_portnum(name)
787c478bd9Sstevel@tonic-gate char *name;
797c478bd9Sstevel@tonic-gate {
807c478bd9Sstevel@tonic-gate struct servent *sp, *sp2;
817c478bd9Sstevel@tonic-gate u_short p1 = 0;
827c478bd9Sstevel@tonic-gate
83ab25eeb5Syz155240 if (ISDIGIT(*name))
847c478bd9Sstevel@tonic-gate return (u_short)atoi(name);
857c478bd9Sstevel@tonic-gate if (!tx_proto)
867c478bd9Sstevel@tonic-gate tx_proto = "tcp/udp";
877c478bd9Sstevel@tonic-gate if (strcasecmp(tx_proto, "tcp/udp")) {
887c478bd9Sstevel@tonic-gate sp = getservbyname(name, tx_proto);
897c478bd9Sstevel@tonic-gate if (sp)
907c478bd9Sstevel@tonic-gate return ntohs(sp->s_port);
917c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "unknown service \"%s\".\n", name);
927c478bd9Sstevel@tonic-gate return 0;
937c478bd9Sstevel@tonic-gate }
947c478bd9Sstevel@tonic-gate sp = getservbyname(name, "tcp");
957c478bd9Sstevel@tonic-gate if (sp)
967c478bd9Sstevel@tonic-gate p1 = sp->s_port;
977c478bd9Sstevel@tonic-gate sp2 = getservbyname(name, "udp");
987c478bd9Sstevel@tonic-gate if (!sp || !sp2) {
997c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "unknown tcp/udp service \"%s\".\n",
1007c478bd9Sstevel@tonic-gate name);
1017c478bd9Sstevel@tonic-gate return 0;
1027c478bd9Sstevel@tonic-gate }
1037c478bd9Sstevel@tonic-gate if (p1 != sp2->s_port) {
1047c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s %d/tcp is a different port to ",
1057c478bd9Sstevel@tonic-gate name, p1);
1067c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s %d/udp\n", name, sp->s_port);
1077c478bd9Sstevel@tonic-gate return 0;
1087c478bd9Sstevel@tonic-gate }
1097c478bd9Sstevel@tonic-gate return ntohs(p1);
1107c478bd9Sstevel@tonic-gate }
1117c478bd9Sstevel@tonic-gate
1127c478bd9Sstevel@tonic-gate
1137c478bd9Sstevel@tonic-gate char *tx_icmptypes[] = {
1147c478bd9Sstevel@tonic-gate "echorep", (char *)NULL, (char *)NULL, "unreach", "squench",
1157c478bd9Sstevel@tonic-gate "redir", (char *)NULL, (char *)NULL, "echo", "routerad",
1167c478bd9Sstevel@tonic-gate "routersol", "timex", "paramprob", "timest", "timestrep",
1177c478bd9Sstevel@tonic-gate "inforeq", "inforep", "maskreq", "maskrep", "END"
1187c478bd9Sstevel@tonic-gate };
1197c478bd9Sstevel@tonic-gate
text_open(fname)1207c478bd9Sstevel@tonic-gate static int text_open(fname)
1217c478bd9Sstevel@tonic-gate char *fname;
1227c478bd9Sstevel@tonic-gate {
1237c478bd9Sstevel@tonic-gate if (tfp && tfd != -1) {
1247c478bd9Sstevel@tonic-gate rewind(tfp);
1257c478bd9Sstevel@tonic-gate return tfd;
1267c478bd9Sstevel@tonic-gate }
1277c478bd9Sstevel@tonic-gate
1287c478bd9Sstevel@tonic-gate if (!strcmp(fname, "-")) {
1297c478bd9Sstevel@tonic-gate tfd = 0;
1307c478bd9Sstevel@tonic-gate tfp = stdin;
1317c478bd9Sstevel@tonic-gate } else {
1327c478bd9Sstevel@tonic-gate tfd = open(fname, O_RDONLY);
1337c478bd9Sstevel@tonic-gate if (tfd != -1)
1347c478bd9Sstevel@tonic-gate tfp = fdopen(tfd, "r");
1357c478bd9Sstevel@tonic-gate }
1367c478bd9Sstevel@tonic-gate return tfd;
1377c478bd9Sstevel@tonic-gate }
1387c478bd9Sstevel@tonic-gate
1397c478bd9Sstevel@tonic-gate
text_close()1407c478bd9Sstevel@tonic-gate static int text_close()
1417c478bd9Sstevel@tonic-gate {
1427c478bd9Sstevel@tonic-gate int cfd = tfd;
1437c478bd9Sstevel@tonic-gate
1447c478bd9Sstevel@tonic-gate tfd = -1;
1457c478bd9Sstevel@tonic-gate return close(cfd);
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate
1487c478bd9Sstevel@tonic-gate
text_readip(buf,cnt,ifn,dir)1497c478bd9Sstevel@tonic-gate static int text_readip(buf, cnt, ifn, dir)
1507c478bd9Sstevel@tonic-gate char *buf, **ifn;
1517c478bd9Sstevel@tonic-gate int cnt, *dir;
1527c478bd9Sstevel@tonic-gate {
1537c478bd9Sstevel@tonic-gate register char *s;
1547c478bd9Sstevel@tonic-gate char line[513];
1557c478bd9Sstevel@tonic-gate
1567c478bd9Sstevel@tonic-gate *ifn = NULL;
1577c478bd9Sstevel@tonic-gate while (fgets(line, sizeof(line)-1, tfp)) {
1587c478bd9Sstevel@tonic-gate if ((s = strchr(line, '\n')))
1597c478bd9Sstevel@tonic-gate *s = '\0';
1607c478bd9Sstevel@tonic-gate if ((s = strchr(line, '\r')))
1617c478bd9Sstevel@tonic-gate *s = '\0';
1627c478bd9Sstevel@tonic-gate if ((s = strchr(line, '#')))
1637c478bd9Sstevel@tonic-gate *s = '\0';
1647c478bd9Sstevel@tonic-gate if (!*line)
1657c478bd9Sstevel@tonic-gate continue;
1667c478bd9Sstevel@tonic-gate if (!(opts & OPT_BRIEF))
1677c478bd9Sstevel@tonic-gate printf("input: %s\n", line);
1687c478bd9Sstevel@tonic-gate *ifn = NULL;
1697c478bd9Sstevel@tonic-gate *dir = 0;
1707c478bd9Sstevel@tonic-gate if (!parseline(line, (ip_t *)buf, ifn, dir))
1717c478bd9Sstevel@tonic-gate #if 0
1727c478bd9Sstevel@tonic-gate return sizeof(ip_t) + sizeof(tcphdr_t);
1737c478bd9Sstevel@tonic-gate #else
1747c478bd9Sstevel@tonic-gate return sizeof(ip_t);
1757c478bd9Sstevel@tonic-gate #endif
1767c478bd9Sstevel@tonic-gate }
1777c478bd9Sstevel@tonic-gate return -1;
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate
parseline(line,ip,ifn,out)1807c478bd9Sstevel@tonic-gate static int parseline(line, ip, ifn, out)
1817c478bd9Sstevel@tonic-gate char *line;
1827c478bd9Sstevel@tonic-gate ip_t *ip;
1837c478bd9Sstevel@tonic-gate char **ifn;
1847c478bd9Sstevel@tonic-gate int *out;
1857c478bd9Sstevel@tonic-gate {
1867c478bd9Sstevel@tonic-gate tcphdr_t th, *tcp = &th;
1877c478bd9Sstevel@tonic-gate struct icmp icmp, *ic = &icmp;
1887c478bd9Sstevel@tonic-gate char *cps[20], **cpp, c, ipopts[68];
1897c478bd9Sstevel@tonic-gate int i, r;
1907c478bd9Sstevel@tonic-gate
1917c478bd9Sstevel@tonic-gate if (*ifn)
1927c478bd9Sstevel@tonic-gate free(*ifn);
1937c478bd9Sstevel@tonic-gate bzero((char *)ip, MAX(sizeof(*tcp), sizeof(*ic)) + sizeof(*ip));
1947c478bd9Sstevel@tonic-gate bzero((char *)tcp, sizeof(*tcp));
1957c478bd9Sstevel@tonic-gate bzero((char *)ic, sizeof(*ic));
1967c478bd9Sstevel@tonic-gate bzero(ipopts, sizeof(ipopts));
1977c478bd9Sstevel@tonic-gate IP_HL_A(ip, sizeof(*ip) >> 2);
1987c478bd9Sstevel@tonic-gate IP_V_A(ip, IPVERSION);
1997c478bd9Sstevel@tonic-gate for (i = 0, cps[0] = strtok(line, " \b\t\r\n"); cps[i] && i < 19; )
2007c478bd9Sstevel@tonic-gate cps[++i] = strtok(NULL, " \b\t\r\n");
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate cpp = cps;
2037c478bd9Sstevel@tonic-gate if (!*cpp)
2047c478bd9Sstevel@tonic-gate return 1;
2057c478bd9Sstevel@tonic-gate
2067c478bd9Sstevel@tonic-gate c = **cpp;
207ab25eeb5Syz155240 if (!ISALPHA(c) || (TOLOWER(c) != 'o' && TOLOWER(c) != 'i')) {
2087c478bd9Sstevel@tonic-gate fprintf(stderr, "bad direction \"%s\"\n", *cpp);
2097c478bd9Sstevel@tonic-gate return 1;
2107c478bd9Sstevel@tonic-gate }
211ab25eeb5Syz155240 *out = (TOLOWER(c) == 'o') ? 1 : 0;
2127c478bd9Sstevel@tonic-gate cpp++;
2137c478bd9Sstevel@tonic-gate if (!*cpp)
2147c478bd9Sstevel@tonic-gate return 1;
2157c478bd9Sstevel@tonic-gate
2167c478bd9Sstevel@tonic-gate if (!strcasecmp(*cpp, "on")) {
2177c478bd9Sstevel@tonic-gate cpp++;
2187c478bd9Sstevel@tonic-gate if (!*cpp)
2197c478bd9Sstevel@tonic-gate return 1;
2207c478bd9Sstevel@tonic-gate *ifn = strdup(*cpp++);
2217c478bd9Sstevel@tonic-gate if (!*cpp)
2227c478bd9Sstevel@tonic-gate return 1;
2237c478bd9Sstevel@tonic-gate }
2247c478bd9Sstevel@tonic-gate
2257c478bd9Sstevel@tonic-gate c = **cpp;
2267c478bd9Sstevel@tonic-gate ip->ip_len = sizeof(ip_t);
2277c478bd9Sstevel@tonic-gate if (!strcasecmp(*cpp, "tcp") || !strcasecmp(*cpp, "udp") ||
2287c478bd9Sstevel@tonic-gate !strcasecmp(*cpp, "icmp")) {
2297c478bd9Sstevel@tonic-gate if (c == 't') {
2307c478bd9Sstevel@tonic-gate ip->ip_p = IPPROTO_TCP;
2317c478bd9Sstevel@tonic-gate ip->ip_len += sizeof(struct tcphdr);
2327c478bd9Sstevel@tonic-gate tx_proto = "tcp";
2337c478bd9Sstevel@tonic-gate } else if (c == 'u') {
2347c478bd9Sstevel@tonic-gate ip->ip_p = IPPROTO_UDP;
2357c478bd9Sstevel@tonic-gate ip->ip_len += sizeof(struct udphdr);
2367c478bd9Sstevel@tonic-gate tx_proto = "udp";
2377c478bd9Sstevel@tonic-gate } else {
2387c478bd9Sstevel@tonic-gate ip->ip_p = IPPROTO_ICMP;
2397c478bd9Sstevel@tonic-gate ip->ip_len += ICMPERR_IPICMPHLEN;
2407c478bd9Sstevel@tonic-gate tx_proto = "icmp";
2417c478bd9Sstevel@tonic-gate }
2427c478bd9Sstevel@tonic-gate cpp++;
243ab25eeb5Syz155240 } else if (ISDIGIT(**cpp) && !index(*cpp, '.')) {
2447c478bd9Sstevel@tonic-gate ip->ip_p = atoi(*cpp);
2457c478bd9Sstevel@tonic-gate cpp++;
2467c478bd9Sstevel@tonic-gate } else
2477c478bd9Sstevel@tonic-gate ip->ip_p = IPPROTO_IP;
2487c478bd9Sstevel@tonic-gate
2497c478bd9Sstevel@tonic-gate if (!*cpp)
2507c478bd9Sstevel@tonic-gate return 1;
2517c478bd9Sstevel@tonic-gate if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) {
2527c478bd9Sstevel@tonic-gate char *last;
2537c478bd9Sstevel@tonic-gate
2547c478bd9Sstevel@tonic-gate last = strchr(*cpp, ',');
2557c478bd9Sstevel@tonic-gate if (!last) {
2567c478bd9Sstevel@tonic-gate fprintf(stderr, "tcp/udp with no source port\n");
2577c478bd9Sstevel@tonic-gate return 1;
2587c478bd9Sstevel@tonic-gate }
2597c478bd9Sstevel@tonic-gate *last++ = '\0';
2607c478bd9Sstevel@tonic-gate tcp->th_sport = htons(tx_portnum(last));
261ab25eeb5Syz155240 if (ip->ip_p == IPPROTO_TCP) {
262ab25eeb5Syz155240 tcp->th_win = htons(4096);
263ab25eeb5Syz155240 TCP_OFF_A(tcp, sizeof(*tcp) >> 2);
264ab25eeb5Syz155240 }
2657c478bd9Sstevel@tonic-gate }
2667c478bd9Sstevel@tonic-gate ip->ip_src.s_addr = tx_hostnum(*cpp, &r);
2677c478bd9Sstevel@tonic-gate cpp++;
2687c478bd9Sstevel@tonic-gate if (!*cpp)
2697c478bd9Sstevel@tonic-gate return 1;
2707c478bd9Sstevel@tonic-gate
2717c478bd9Sstevel@tonic-gate if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) {
2727c478bd9Sstevel@tonic-gate char *last;
2737c478bd9Sstevel@tonic-gate
2747c478bd9Sstevel@tonic-gate last = strchr(*cpp, ',');
2757c478bd9Sstevel@tonic-gate if (!last) {
2767c478bd9Sstevel@tonic-gate fprintf(stderr, "tcp/udp with no destination port\n");
2777c478bd9Sstevel@tonic-gate return 1;
2787c478bd9Sstevel@tonic-gate }
2797c478bd9Sstevel@tonic-gate *last++ = '\0';
2807c478bd9Sstevel@tonic-gate tcp->th_dport = htons(tx_portnum(last));
2817c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate ip->ip_dst.s_addr = tx_hostnum(*cpp, &r);
2837c478bd9Sstevel@tonic-gate cpp++;
2847c478bd9Sstevel@tonic-gate if (*cpp && ip->ip_p == IPPROTO_TCP) {
2857c478bd9Sstevel@tonic-gate char *s, *t;
2867c478bd9Sstevel@tonic-gate
287ab25eeb5Syz155240 tcp->th_flags = 0;
2887c478bd9Sstevel@tonic-gate for (s = *cpp; *s; s++)
289ab25eeb5Syz155240 if ((t = strchr(myflagset, *s)))
290ab25eeb5Syz155240 tcp->th_flags |= myflags[t - myflagset];
2917c478bd9Sstevel@tonic-gate if (tcp->th_flags)
2927c478bd9Sstevel@tonic-gate cpp++;
2937c478bd9Sstevel@tonic-gate if (tcp->th_flags == 0)
2947c478bd9Sstevel@tonic-gate abort();
295ab25eeb5Syz155240 if (tcp->th_flags & TH_URG)
296ab25eeb5Syz155240 tcp->th_urp = htons(1);
2977c478bd9Sstevel@tonic-gate } else if (*cpp && ip->ip_p == IPPROTO_ICMP) {
2987c478bd9Sstevel@tonic-gate extern char *tx_icmptypes[];
2997c478bd9Sstevel@tonic-gate char **s, *t;
3007c478bd9Sstevel@tonic-gate int i;
3017c478bd9Sstevel@tonic-gate
3027c478bd9Sstevel@tonic-gate for (s = tx_icmptypes, i = 0; !*s || strcmp(*s, "END");
3037c478bd9Sstevel@tonic-gate s++, i++)
3047c478bd9Sstevel@tonic-gate if (*s && !strncasecmp(*cpp, *s, strlen(*s))) {
3057c478bd9Sstevel@tonic-gate ic->icmp_type = i;
3067c478bd9Sstevel@tonic-gate if ((t = strchr(*cpp, ',')))
3077c478bd9Sstevel@tonic-gate ic->icmp_code = atoi(t+1);
3087c478bd9Sstevel@tonic-gate cpp++;
3097c478bd9Sstevel@tonic-gate break;
3107c478bd9Sstevel@tonic-gate }
3117c478bd9Sstevel@tonic-gate }
3127c478bd9Sstevel@tonic-gate
3137c478bd9Sstevel@tonic-gate if (*cpp && !strcasecmp(*cpp, "opt")) {
3147c478bd9Sstevel@tonic-gate u_long olen;
3157c478bd9Sstevel@tonic-gate
3167c478bd9Sstevel@tonic-gate cpp++;
3177c478bd9Sstevel@tonic-gate olen = buildopts(*cpp, ipopts, (IP_HL(ip) - 5) << 2);
3187c478bd9Sstevel@tonic-gate if (olen) {
3197c478bd9Sstevel@tonic-gate bcopy(ipopts, (char *)(ip + 1), olen);
3207c478bd9Sstevel@tonic-gate IP_HL_A(ip, IP_HL(ip) + (olen >> 2));
3217c478bd9Sstevel@tonic-gate }
3227c478bd9Sstevel@tonic-gate }
3237c478bd9Sstevel@tonic-gate if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP)
3247c478bd9Sstevel@tonic-gate bcopy((char *)tcp, ((char *)ip) + (IP_HL(ip) << 2),
3257c478bd9Sstevel@tonic-gate sizeof(*tcp));
3267c478bd9Sstevel@tonic-gate else if (ip->ip_p == IPPROTO_ICMP)
3277c478bd9Sstevel@tonic-gate bcopy((char *)ic, ((char *)ip) + (IP_HL(ip) << 2),
3287c478bd9Sstevel@tonic-gate sizeof(*ic));
3297c478bd9Sstevel@tonic-gate ip->ip_len = htons(ip->ip_len);
3307c478bd9Sstevel@tonic-gate return 0;
3317c478bd9Sstevel@tonic-gate }
332