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