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