1 /* $FreeBSD$ */ 2 3 /* 4 * Copyright (C) 2012 by Darren Reed. 5 * 6 * See the IPFILTER.LICENCE file for details on licencing. 7 * 8 * $Id$ 9 */ 10 #if !defined(lint) 11 static const char sccsid[] = "@(#)ipft_tx.c 1.7 6/5/96 (C) 1993 Darren Reed"; 12 static const char rcsid[] = "@(#)$Id$"; 13 #endif 14 15 #include <ctype.h> 16 17 #include "ipf.h" 18 #include "ipt.h" 19 20 extern int opts; 21 22 static char *tx_proto = ""; 23 24 static int text_open(char *), text_close(void); 25 static int text_readip(mb_t *, char **, int *); 26 static int parseline(char *, ip_t *, char **, int *); 27 28 static char myflagset[] = "FSRPAUEC"; 29 static u_char myflags[] = { TH_FIN, TH_SYN, TH_RST, TH_PUSH, 30 TH_ACK, TH_URG, TH_ECN, TH_CWR }; 31 32 struct ipread iptext = { text_open, text_close, text_readip, R_DO_CKSUM }; 33 static FILE *tfp = NULL; 34 static int tfd = -1; 35 36 static u_32_t tx_hostnum(char *, int *); 37 static u_short tx_portnum(char *); 38 39 #ifdef USE_INET6 40 int parseipv6(char **, ip6_t *, char **, int *); 41 #endif 42 43 /* 44 * returns an ip address as a long var as a result of either a DNS lookup or 45 * straight inet_addr() call 46 */ 47 static u_32_t 48 tx_hostnum(char *host, int *resolved) 49 { 50 i6addr_t ipa; 51 52 *resolved = 0; 53 if (!strcasecmp("any", host)) 54 return (0L); 55 if (ISDIGIT(*host)) 56 return (inet_addr(host)); 57 58 if (gethost(AF_INET, host, &ipa) == -1) { 59 *resolved = -1; 60 fprintf(stderr, "can't resolve hostname: %s\n", host); 61 return (0); 62 } 63 return (ipa.in4.s_addr); 64 } 65 66 67 /* 68 * find the port number given by the name, either from getservbyname() or 69 * straight atoi() 70 */ 71 static u_short 72 tx_portnum(char *name) 73 { 74 struct servent *sp; 75 76 if (ISDIGIT(*name)) 77 return (u_short)atoi(name); 78 sp = getservbyname(name, tx_proto); 79 if (sp) 80 return (ntohs(sp->s_port)); 81 (void) fprintf(stderr, "unknown service \"%s\".\n", name); 82 return (0); 83 } 84 85 86 static int 87 text_open(char *fname) 88 { 89 if (tfp && tfd != -1) { 90 rewind(tfp); 91 return (tfd); 92 } 93 94 if (!strcmp(fname, "-")) { 95 tfd = 0; 96 tfp = stdin; 97 } else { 98 tfd = open(fname, O_RDONLY); 99 if (tfd != -1) 100 tfp = fdopen(tfd, "r"); 101 } 102 return (tfd); 103 } 104 105 106 static int 107 text_close(void) 108 { 109 int cfd = tfd; 110 111 tfd = -1; 112 return (close(cfd)); 113 } 114 115 116 static int 117 text_readip(mb_t *mb, char **ifn, int *dir) 118 { 119 register char *s; 120 char line[513]; 121 ip_t *ip; 122 char *buf; 123 124 buf = (char *)mb->mb_buf; 125 126 *ifn = NULL; 127 while (fgets(line, sizeof(line)-1, tfp)) { 128 if ((s = strchr(line, '\n'))) 129 *s = '\0'; 130 if ((s = strchr(line, '\r'))) 131 *s = '\0'; 132 if ((s = strchr(line, '#'))) 133 *s = '\0'; 134 if (!*line) 135 continue; 136 if ((opts & OPT_DEBUG) != 0) 137 printf("input: %s\n", line); 138 *ifn = NULL; 139 *dir = 0; 140 if (!parseline(line, (ip_t *)buf, ifn, dir)) { 141 ip = (ip_t *)buf; 142 if (IP_V(ip) == 6) { 143 #ifdef USE_INET6 144 mb->mb_len = ntohs(((ip6_t *)ip)->ip6_plen) + 145 sizeof(ip6_t); 146 #else 147 mb->mb_len = 0; 148 #endif 149 } else { 150 mb->mb_len = ntohs(ip->ip_len); 151 } 152 return (mb->mb_len); 153 } 154 } 155 if (feof(tfp)) 156 return (0); 157 return (-1); 158 } 159 160 static int 161 parseline(char *line, ip_t *ip, char **ifn, int *out) 162 { 163 tcphdr_t th, *tcp = &th; 164 struct icmp icmp, *ic = &icmp; 165 char *cps[20], **cpp, c, ipopts[68]; 166 int i, r; 167 168 if (*ifn) 169 free(*ifn); 170 bzero((char *)ip, MAX(sizeof(*tcp), sizeof(*ic)) + sizeof(*ip)); 171 bzero((char *)tcp, sizeof(*tcp)); 172 bzero((char *)ic, sizeof(*ic)); 173 bzero(ipopts, sizeof(ipopts)); 174 IP_HL_A(ip, sizeof(*ip) >> 2); 175 IP_V_A(ip, IPVERSION); 176 ip->ip_ttl = 63; 177 for (i = 0, cps[0] = strtok(line, " \b\t\r\n"); cps[i] && i < 19; ) 178 cps[++i] = strtok(NULL, " \b\t\r\n"); 179 180 cpp = cps; 181 if (!*cpp) 182 return (1); 183 184 c = **cpp; 185 if (!ISALPHA(c) || (TOLOWER(c) != 'o' && TOLOWER(c) != 'i')) { 186 fprintf(stderr, "bad direction \"%s\"\n", *cpp); 187 return (1); 188 } 189 190 #ifdef USE_INET6 191 if (!strcasecmp(*cpp, "out6") || !strcasecmp(*cpp, "in6")) { 192 return (parseipv6(cpp, (ip6_t *)ip, ifn, out)); 193 } 194 #endif 195 196 *out = (TOLOWER(c) == 'o') ? 1 : 0; 197 cpp++; 198 if (!*cpp) 199 return (1); 200 201 if (!strcasecmp(*cpp, "on")) { 202 cpp++; 203 if (!*cpp) 204 return (1); 205 *ifn = strdup(*cpp++); 206 if (!*cpp) 207 return (1); 208 } 209 210 c = **cpp; 211 ip->ip_len = sizeof(ip_t); 212 if (!strcasecmp(*cpp, "tcp") || !strcasecmp(*cpp, "udp") || 213 !strcasecmp(*cpp, "icmp")) { 214 if (c == 't') { 215 ip->ip_p = IPPROTO_TCP; 216 ip->ip_len += sizeof(struct tcphdr); 217 tx_proto = "tcp"; 218 } else if (c == 'u') { 219 ip->ip_p = IPPROTO_UDP; 220 ip->ip_len += sizeof(struct udphdr); 221 tx_proto = "udp"; 222 } else { 223 ip->ip_p = IPPROTO_ICMP; 224 ip->ip_len += ICMPERR_IPICMPHLEN; 225 tx_proto = "icmp"; 226 } 227 cpp++; 228 } else if (ISDIGIT(**cpp) && !index(*cpp, '.')) { 229 ip->ip_p = atoi(*cpp); 230 cpp++; 231 } else 232 ip->ip_p = IPPROTO_IP; 233 234 if (!*cpp) 235 return (1); 236 if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) { 237 char *last; 238 239 last = strchr(*cpp, ','); 240 if (!last) { 241 fprintf(stderr, "tcp/udp with no source port\n"); 242 return (1); 243 } 244 *last++ = '\0'; 245 tcp->th_sport = htons(tx_portnum(last)); 246 if (ip->ip_p == IPPROTO_TCP) { 247 tcp->th_win = htons(4096); 248 TCP_OFF_A(tcp, sizeof(*tcp) >> 2); 249 } 250 } 251 ip->ip_src.s_addr = tx_hostnum(*cpp, &r); 252 cpp++; 253 if (!*cpp) 254 return (1); 255 256 if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) { 257 char *last; 258 259 last = strchr(*cpp, ','); 260 if (!last) { 261 fprintf(stderr, "tcp/udp with no destination port\n"); 262 return (1); 263 } 264 *last++ = '\0'; 265 tcp->th_dport = htons(tx_portnum(last)); 266 } 267 ip->ip_dst.s_addr = tx_hostnum(*cpp, &r); 268 cpp++; 269 if (ip->ip_p == IPPROTO_TCP) { 270 if (*cpp != NULL) { 271 char *s, *t; 272 273 tcp->th_flags = 0; 274 for (s = *cpp; *s; s++) 275 if ((t = strchr(myflagset, *s))) 276 tcp->th_flags |= myflags[t-myflagset]; 277 if (tcp->th_flags) 278 cpp++; 279 } 280 281 if (tcp->th_flags & TH_URG) 282 tcp->th_urp = htons(1); 283 284 if (*cpp && !strncasecmp(*cpp, "seq=", 4)) { 285 tcp->th_seq = htonl(atoi(*cpp + 4)); 286 cpp++; 287 } 288 289 if (*cpp && !strncasecmp(*cpp, "ack=", 4)) { 290 tcp->th_ack = htonl(atoi(*cpp + 4)); 291 cpp++; 292 } 293 } else if (*cpp && ip->ip_p == IPPROTO_ICMP) { 294 char *t; 295 296 t = strchr(*cpp, ','); 297 if (t != NULL) 298 *t = '\0'; 299 300 ic->icmp_type = geticmptype(AF_INET, *cpp); 301 if (t != NULL) 302 ic->icmp_code = atoi(t + 1); 303 cpp++; 304 305 if (ic->icmp_type == ICMP_ECHO || 306 ic->icmp_type == ICMP_ECHOREPLY) 307 ic->icmp_id = htons(getpid()); 308 if (t != NULL) 309 *t = ','; 310 } 311 312 if (*cpp && !strcasecmp(*cpp, "opt")) { 313 u_long olen; 314 315 cpp++; 316 olen = buildopts(*cpp, ipopts, (IP_HL(ip) - 5) << 2); 317 if (olen) { 318 bcopy(ipopts, (char *)(ip + 1), olen); 319 IP_HL_A(ip, IP_HL(ip) + (olen >> 2)); 320 ip->ip_len += olen; 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 333 334 #ifdef USE_INET6 335 int 336 parseipv6(char **cpp, ip6_t *ip6, char **ifn, int *out) 337 { 338 tcphdr_t th, *tcp = &th; 339 struct icmp6_hdr icmp, *ic6 = &icmp; 340 341 bzero((char *)ip6, MAX(sizeof(*tcp), sizeof(*ic6)) + sizeof(*ip6)); 342 bzero((char *)tcp, sizeof(*tcp)); 343 bzero((char *)ic6, sizeof(*ic6)); 344 ip6->ip6_vfc = 0x60; 345 346 *out = (**cpp == 'o') ? 1 : 0; 347 cpp++; 348 if (!*cpp) 349 return (1); 350 351 if (!strcasecmp(*cpp, "on")) { 352 cpp++; 353 if (!*cpp) 354 return (1); 355 *ifn = strdup(*cpp++); 356 if (!*cpp) 357 return (1); 358 } 359 360 if (!strcasecmp(*cpp, "tcp")) { 361 ip6->ip6_nxt = IPPROTO_TCP; 362 tx_proto = "tcp"; 363 cpp++; 364 } else if (!strcasecmp(*cpp, "udp")) { 365 ip6->ip6_nxt = IPPROTO_UDP; 366 tx_proto = "udp"; 367 cpp++; 368 } else if (!strcasecmp(*cpp, "icmpv6")) { 369 ip6->ip6_nxt = IPPROTO_ICMPV6; 370 tx_proto = "icmpv6"; 371 cpp++; 372 } else if (ISDIGIT(**cpp) && !index(*cpp, ':')) { 373 ip6->ip6_nxt = atoi(*cpp); 374 cpp++; 375 } else 376 ip6->ip6_nxt = IPPROTO_IPV6; 377 378 if (!*cpp) 379 return (1); 380 381 switch (ip6->ip6_nxt) 382 { 383 case IPPROTO_TCP : 384 ip6->ip6_plen = sizeof(struct tcphdr); 385 break; 386 case IPPROTO_UDP : 387 ip6->ip6_plen = sizeof(struct udphdr); 388 break; 389 case IPPROTO_ICMPV6 : 390 ip6->ip6_plen = ICMP6ERR_IPICMPHLEN; 391 break; 392 default : 393 break; 394 } 395 396 if (ip6->ip6_nxt == IPPROTO_TCP || ip6->ip6_nxt == IPPROTO_UDP) { 397 char *last; 398 399 last = strchr(*cpp, ','); 400 if (!last) { 401 fprintf(stderr, "tcp/udp with no source port\n"); 402 return (1); 403 } 404 *last++ = '\0'; 405 tcp->th_sport = htons(tx_portnum(last)); 406 if (ip6->ip6_nxt == IPPROTO_TCP) { 407 tcp->th_win = htons(4096); 408 TCP_OFF_A(tcp, sizeof(*tcp) >> 2); 409 } 410 } 411 412 if (inet_pton(AF_INET6, *cpp, &ip6->ip6_src) != 1) { 413 fprintf(stderr, "cannot parse source address '%s'\n", *cpp); 414 return (1); 415 } 416 417 cpp++; 418 if (!*cpp) 419 return (1); 420 421 if (ip6->ip6_nxt == IPPROTO_TCP || ip6->ip6_nxt == IPPROTO_UDP) { 422 char *last; 423 424 last = strchr(*cpp, ','); 425 if (!last) { 426 fprintf(stderr, "tcp/udp with no destination port\n"); 427 return (1); 428 } 429 *last++ = '\0'; 430 tcp->th_dport = htons(tx_portnum(last)); 431 } 432 433 if (inet_pton(AF_INET6, *cpp, &ip6->ip6_dst) != 1) { 434 fprintf(stderr, "cannot parse destination address '%s'\n", 435 *cpp); 436 return (1); 437 } 438 439 cpp++; 440 if (ip6->ip6_nxt == IPPROTO_TCP) { 441 if (*cpp != NULL) { 442 char *s, *t; 443 444 tcp->th_flags = 0; 445 for (s = *cpp; *s; s++) 446 if ((t = strchr(myflagset, *s))) 447 tcp->th_flags |= myflags[t-myflagset]; 448 if (tcp->th_flags) 449 cpp++; 450 } 451 452 if (tcp->th_flags & TH_URG) 453 tcp->th_urp = htons(1); 454 455 if (*cpp && !strncasecmp(*cpp, "seq=", 4)) { 456 tcp->th_seq = htonl(atoi(*cpp + 4)); 457 cpp++; 458 } 459 460 if (*cpp && !strncasecmp(*cpp, "ack=", 4)) { 461 tcp->th_ack = htonl(atoi(*cpp + 4)); 462 cpp++; 463 } 464 } else if (*cpp && ip6->ip6_nxt == IPPROTO_ICMPV6) { 465 char *t; 466 467 t = strchr(*cpp, ','); 468 if (t != NULL) 469 *t = '\0'; 470 471 ic6->icmp6_type = geticmptype(AF_INET6, *cpp); 472 if (t != NULL) 473 ic6->icmp6_code = atoi(t + 1); 474 475 if (ic6->icmp6_type == ICMP6_ECHO_REQUEST || 476 ic6->icmp6_type == ICMP6_ECHO_REPLY) 477 ic6->icmp6_id = htons(getpid()); 478 479 if (t != NULL) 480 *t = ','; 481 } 482 483 if (ip6->ip6_nxt == IPPROTO_TCP || ip6->ip6_nxt == IPPROTO_UDP) { 484 bcopy((char *)tcp, (char *)ip6 + sizeof(*ip6), 485 sizeof(*tcp)); 486 } else if (ip6->ip6_nxt == IPPROTO_ICMPV6) { 487 bcopy((char *)ic6, (char *)ip6 + sizeof(*ip6), 488 sizeof(*ic6)); 489 } 490 491 /* 492 * Because a length of 0 == jumbo gram... 493 */ 494 if (ip6->ip6_plen == 0) { 495 ip6->ip6_plen++; 496 } 497 ip6->ip6_plen = htons(ip6->ip6_plen); 498 return (0); 499 } 500 #endif 501