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