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