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 #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: ipft_tx.c,v 1.15.2.3 2005/06/18 02:41:34 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 26 extern int opts; 27 28 static char *tx_proto = ""; 29 30 static int text_open __P((char *)), text_close __P((void)); 31 static int text_readip __P((char *, int, char **, int *)); 32 static int parseline __P((char *, ip_t *, char **, int *)); 33 34 static char myflagset[] = "FSRPAUEC"; 35 static u_char myflags[] = { TH_FIN, TH_SYN, TH_RST, TH_PUSH, 36 TH_ACK, TH_URG, TH_ECN, TH_CWR }; 37 38 struct ipread iptext = { text_open, text_close, text_readip, R_DO_CKSUM }; 39 static FILE *tfp = NULL; 40 static int tfd = -1; 41 42 static u_32_t tx_hostnum __P((char *, int *)); 43 static 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 */ 50 static u_32_t tx_hostnum(host, resolved) 51 char *host; 52 int *resolved; 53 { 54 i6addr_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, 0) == -1) { 63 *resolved = -1; 64 fprintf(stderr, "can't resolve hostname: %s\n", host); 65 return 0; 66 } 67 return ipa.in4_addr; 68 } 69 70 71 /* 72 * find the port number given by the name, either from getservbyname() or 73 * straight atoi() 74 */ 75 static u_short tx_portnum(name) 76 char *name; 77 { 78 struct servent *sp, *sp2; 79 u_short p1 = 0; 80 81 if (ISDIGIT(*name)) 82 return (u_short)atoi(name); 83 if (!tx_proto) 84 tx_proto = "tcp/udp"; 85 if (strcasecmp(tx_proto, "tcp/udp")) { 86 sp = getservbyname(name, tx_proto); 87 if (sp) 88 return ntohs(sp->s_port); 89 (void) fprintf(stderr, "unknown service \"%s\".\n", name); 90 return 0; 91 } 92 sp = getservbyname(name, "tcp"); 93 if (sp) 94 p1 = sp->s_port; 95 sp2 = getservbyname(name, "udp"); 96 if (!sp || !sp2) { 97 (void) fprintf(stderr, "unknown tcp/udp service \"%s\".\n", 98 name); 99 return 0; 100 } 101 if (p1 != sp2->s_port) { 102 (void) fprintf(stderr, "%s %d/tcp is a different port to ", 103 name, p1); 104 (void) fprintf(stderr, "%s %d/udp\n", name, sp->s_port); 105 return 0; 106 } 107 return ntohs(p1); 108 } 109 110 111 char *tx_icmptypes[] = { 112 "echorep", (char *)NULL, (char *)NULL, "unreach", "squench", 113 "redir", (char *)NULL, (char *)NULL, "echo", "routerad", 114 "routersol", "timex", "paramprob", "timest", "timestrep", 115 "inforeq", "inforep", "maskreq", "maskrep", "END" 116 }; 117 118 static int text_open(fname) 119 char *fname; 120 { 121 if (tfp && tfd != -1) { 122 rewind(tfp); 123 return tfd; 124 } 125 126 if (!strcmp(fname, "-")) { 127 tfd = 0; 128 tfp = stdin; 129 } else { 130 tfd = open(fname, O_RDONLY); 131 if (tfd != -1) 132 tfp = fdopen(tfd, "r"); 133 } 134 return tfd; 135 } 136 137 138 static int text_close() 139 { 140 int cfd = tfd; 141 142 tfd = -1; 143 return close(cfd); 144 } 145 146 147 static int text_readip(buf, cnt, ifn, dir) 148 char *buf, **ifn; 149 int cnt, *dir; 150 { 151 register char *s; 152 char line[513]; 153 154 *ifn = NULL; 155 while (fgets(line, sizeof(line)-1, tfp)) { 156 if ((s = strchr(line, '\n'))) 157 *s = '\0'; 158 if ((s = strchr(line, '\r'))) 159 *s = '\0'; 160 if ((s = strchr(line, '#'))) 161 *s = '\0'; 162 if (!*line) 163 continue; 164 if (!(opts & OPT_BRIEF)) 165 printf("input: %s\n", line); 166 *ifn = NULL; 167 *dir = 0; 168 if (!parseline(line, (ip_t *)buf, ifn, dir)) 169 #if 0 170 return sizeof(ip_t) + sizeof(tcphdr_t); 171 #else 172 return sizeof(ip_t); 173 #endif 174 } 175 return -1; 176 } 177 178 static int parseline(line, ip, ifn, out) 179 char *line; 180 ip_t *ip; 181 char **ifn; 182 int *out; 183 { 184 tcphdr_t th, *tcp = &th; 185 struct icmp icmp, *ic = &icmp; 186 char *cps[20], **cpp, c, ipopts[68]; 187 int i, r; 188 189 if (*ifn) 190 free(*ifn); 191 bzero((char *)ip, MAX(sizeof(*tcp), sizeof(*ic)) + sizeof(*ip)); 192 bzero((char *)tcp, sizeof(*tcp)); 193 bzero((char *)ic, sizeof(*ic)); 194 bzero(ipopts, sizeof(ipopts)); 195 IP_HL_A(ip, sizeof(*ip) >> 2); 196 IP_V_A(ip, IPVERSION); 197 for (i = 0, cps[0] = strtok(line, " \b\t\r\n"); cps[i] && i < 19; ) 198 cps[++i] = strtok(NULL, " \b\t\r\n"); 199 200 cpp = cps; 201 if (!*cpp) 202 return 1; 203 204 c = **cpp; 205 if (!ISALPHA(c) || (TOLOWER(c) != 'o' && TOLOWER(c) != 'i')) { 206 fprintf(stderr, "bad direction \"%s\"\n", *cpp); 207 return 1; 208 } 209 *out = (TOLOWER(c) == 'o') ? 1 : 0; 210 cpp++; 211 if (!*cpp) 212 return 1; 213 214 if (!strcasecmp(*cpp, "on")) { 215 cpp++; 216 if (!*cpp) 217 return 1; 218 *ifn = strdup(*cpp++); 219 if (!*cpp) 220 return 1; 221 } 222 223 c = **cpp; 224 ip->ip_len = sizeof(ip_t); 225 if (!strcasecmp(*cpp, "tcp") || !strcasecmp(*cpp, "udp") || 226 !strcasecmp(*cpp, "icmp")) { 227 if (c == 't') { 228 ip->ip_p = IPPROTO_TCP; 229 ip->ip_len += sizeof(struct tcphdr); 230 tx_proto = "tcp"; 231 } else if (c == 'u') { 232 ip->ip_p = IPPROTO_UDP; 233 ip->ip_len += sizeof(struct udphdr); 234 tx_proto = "udp"; 235 } else { 236 ip->ip_p = IPPROTO_ICMP; 237 ip->ip_len += ICMPERR_IPICMPHLEN; 238 tx_proto = "icmp"; 239 } 240 cpp++; 241 } else if (ISDIGIT(**cpp) && !index(*cpp, '.')) { 242 ip->ip_p = atoi(*cpp); 243 cpp++; 244 } else 245 ip->ip_p = IPPROTO_IP; 246 247 if (!*cpp) 248 return 1; 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 source port\n"); 255 return 1; 256 } 257 *last++ = '\0'; 258 tcp->th_sport = htons(tx_portnum(last)); 259 if (ip->ip_p == IPPROTO_TCP) { 260 tcp->th_win = htons(4096); 261 TCP_OFF_A(tcp, sizeof(*tcp) >> 2); 262 } 263 } 264 ip->ip_src.s_addr = tx_hostnum(*cpp, &r); 265 cpp++; 266 if (!*cpp) 267 return 1; 268 269 if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) { 270 char *last; 271 272 last = strchr(*cpp, ','); 273 if (!last) { 274 fprintf(stderr, "tcp/udp with no destination port\n"); 275 return 1; 276 } 277 *last++ = '\0'; 278 tcp->th_dport = htons(tx_portnum(last)); 279 } 280 ip->ip_dst.s_addr = tx_hostnum(*cpp, &r); 281 cpp++; 282 if (*cpp && ip->ip_p == IPPROTO_TCP) { 283 char *s, *t; 284 285 tcp->th_flags = 0; 286 for (s = *cpp; *s; s++) 287 if ((t = strchr(myflagset, *s))) 288 tcp->th_flags |= myflags[t - myflagset]; 289 if (tcp->th_flags) 290 cpp++; 291 if (tcp->th_flags == 0) 292 abort(); 293 if (tcp->th_flags & TH_URG) 294 tcp->th_urp = htons(1); 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