ip.c revision 37572
1228753Smm/* 2228753Smm * PPP IP Protocol Interface 3228753Smm * 4228753Smm * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5228753Smm * 6228753Smm * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7228753Smm * 8228753Smm * Redistribution and use in source and binary forms are permitted 9228753Smm * provided that the above copyright notice and this paragraph are 10228753Smm * duplicated in all such forms and that any documentation, 11228753Smm * advertising materials, and other materials related to such 12228753Smm * distribution and use acknowledge that the software was developed 13228753Smm * by the Internet Initiative Japan. The name of the 14228753Smm * IIJ may not be used to endorse or promote products derived 15228753Smm * from this software without specific prior written permission. 16228753Smm * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17228753Smm * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18228753Smm * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19228753Smm * 20228753Smm * $Id: ip.c,v 1.48 1998/06/27 23:48:45 brian Exp $ 21228753Smm * 22228753Smm * TODO: 23228753Smm * o Return ICMP message for filterd packet 24228753Smm * and optionaly record it into log. 25228753Smm */ 26229592Smm#include <sys/types.h> 27228753Smm#include <sys/socket.h> 28228753Smm#include <netinet/in.h> 29228753Smm#include <netinet/in_systm.h> 30228753Smm#include <netinet/ip.h> 31228753Smm#include <netinet/ip_icmp.h> 32228753Smm#include <netinet/udp.h> 33228753Smm#include <netinet/tcp.h> 34228753Smm#include <arpa/inet.h> 35228753Smm#include <sys/un.h> 36228753Smm 37228753Smm#ifndef NOALIAS 38228753Smm#include <alias.h> 39228753Smm#endif 40228753Smm#include <errno.h> 41228753Smm#include <stdio.h> 42228753Smm#include <stdlib.h> 43228753Smm#include <string.h> 44228753Smm#include <unistd.h> 45228753Smm 46228753Smm#include "mbuf.h" 47228753Smm#include "log.h" 48228753Smm#include "defs.h" 49228753Smm#include "timer.h" 50228753Smm#include "fsm.h" 51228753Smm#include "lqr.h" 52228753Smm#include "hdlc.h" 53228753Smm#include "throughput.h" 54228753Smm#include "iplist.h" 55228753Smm#include "slcompress.h" 56228753Smm#include "ipcp.h" 57228753Smm#include "filter.h" 58228753Smm#include "descriptor.h" 59228753Smm#include "lcp.h" 60228753Smm#include "ccp.h" 61228753Smm#include "link.h" 62228753Smm#include "mp.h" 63228753Smm#include "bundle.h" 64228753Smm#include "vjcomp.h" 65228753Smm#include "tun.h" 66228753Smm#include "ip.h" 67228753Smm 68228753Smmstatic const u_short interactive_ports[32] = { 69228753Smm 544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70228753Smm 0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543, 71228753Smm}; 72228753Smm 73228753Smm#define INTERACTIVE(p) (interactive_ports[(p) & 0x1F] == (p)) 74228753Smm 75228753Smmstatic const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" }; 76228753Smm 77static int 78PortMatch(int op, u_short pport, u_short rport) 79{ 80 switch (op) { 81 case OP_EQ: 82 return (pport == rport); 83 case OP_GT: 84 return (pport > rport); 85 case OP_LT: 86 return (pport < rport); 87 default: 88 return (0); 89 } 90} 91 92/* 93 * Check a packet against with defined filters 94 */ 95static int 96FilterCheck(struct ip *pip, struct filter *filter) 97{ 98 int gotinfo, cproto, estab, syn, finrst, n, len, didname; 99 struct tcphdr *th; 100 struct udphdr *uh; 101 struct icmp *ih; 102 char *ptop; 103 u_short sport, dport; 104 struct filterent *fp = filter->rule; 105 char dbuff[100]; 106 107 if (fp->action) { 108 cproto = gotinfo = estab = syn = finrst = didname = 0; 109 sport = dport = 0; 110 for (n = 0; n < MAXFILTERS; n++) { 111 if (fp->action) { 112 /* permit fragments on in and out filter */ 113 if (filter->fragok && (ntohs(pip->ip_off) & IP_OFFMASK) != 0) 114 return (A_PERMIT); 115 116 if (!didname) 117 log_Printf(LogDEBUG, "%s filter:\n", filter->name); 118 didname = 1; 119 120 if ((pip->ip_src.s_addr & fp->smask.s_addr) == 121 (fp->saddr.s_addr & fp->smask.s_addr) && 122 (pip->ip_dst.s_addr & fp->dmask.s_addr) == 123 (fp->daddr.s_addr & fp->dmask.s_addr)) { 124 if (fp->proto) { 125 if (!gotinfo) { 126 ptop = (char *) pip + (pip->ip_hl << 2); 127 128 switch (pip->ip_p) { 129 case IPPROTO_ICMP: 130 cproto = P_ICMP; 131 ih = (struct icmp *) ptop; 132 sport = ih->icmp_type; 133 estab = syn = finrst = -1; 134 if (log_IsKept(LogDEBUG)) 135 snprintf(dbuff, sizeof dbuff, "sport = %d", sport); 136 break; 137 case IPPROTO_UDP: 138 case IPPROTO_IGMP: 139 case IPPROTO_IPIP: 140 cproto = P_UDP; 141 uh = (struct udphdr *) ptop; 142 sport = ntohs(uh->uh_sport); 143 dport = ntohs(uh->uh_dport); 144 estab = syn = finrst = -1; 145 if (log_IsKept(LogDEBUG)) 146 snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d", 147 sport, dport); 148 break; 149 case IPPROTO_TCP: 150 cproto = P_TCP; 151 th = (struct tcphdr *) ptop; 152 sport = ntohs(th->th_sport); 153 dport = ntohs(th->th_dport); 154 estab = (th->th_flags & TH_ACK); 155 syn = (th->th_flags & TH_SYN); 156 finrst = (th->th_flags & (TH_FIN|TH_RST)); 157 if (log_IsKept(LogDEBUG) && !estab) 158 snprintf(dbuff, sizeof dbuff, 159 "flags = %02x, sport = %d, dport = %d", 160 th->th_flags, sport, dport); 161 break; 162 default: 163 return (A_DENY); /* We'll block unknown type of packet */ 164 } 165 if (log_IsKept(LogDEBUG)) { 166 if (estab != -1) { 167 len = strlen(dbuff); 168 snprintf(dbuff + len, sizeof dbuff - len, 169 ", estab = %d, syn = %d, finrst = %d", 170 estab, syn, finrst); 171 } 172 log_Printf(LogDEBUG, " Filter: proto = %s, %s\n", 173 filter_Proto2Nam(cproto), dbuff); 174 } 175 gotinfo = 1; 176 } 177 if (log_IsKept(LogDEBUG)) { 178 if (fp->opt.srcop != OP_NONE) { 179 snprintf(dbuff, sizeof dbuff, ", src %s %d", 180 filter_Op2Nam(fp->opt.srcop), fp->opt.srcport); 181 len = strlen(dbuff); 182 } else 183 len = 0; 184 if (fp->opt.dstop != OP_NONE) { 185 snprintf(dbuff + len, sizeof dbuff - len, 186 ", dst %s %d", filter_Op2Nam(fp->opt.dstop), 187 fp->opt.dstport); 188 } else if (!len) 189 *dbuff = '\0'; 190 191 log_Printf(LogDEBUG, " rule = %d: Address match, " 192 "check against proto %s%s, action = %s\n", 193 n, filter_Proto2Nam(fp->proto), 194 dbuff, filter_Action2Nam(fp->action)); 195 } 196 197 if (cproto == fp->proto) { 198 if ((fp->opt.srcop == OP_NONE || 199 PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) && 200 (fp->opt.dstop == OP_NONE || 201 PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) && 202 (fp->opt.estab == 0 || estab) && 203 (fp->opt.syn == 0 || syn) && 204 (fp->opt.finrst == 0 || finrst)) { 205 return (fp->action); 206 } 207 } 208 } else { 209 /* Address is mached. Make a decision. */ 210 log_Printf(LogDEBUG, " rule = %d: Address match, action = %s\n", n, 211 filter_Action2Nam(fp->action)); 212 return (fp->action); 213 } 214 } else 215 log_Printf(LogDEBUG, " rule = %d: Address mismatch\n", n); 216 } 217 fp++; 218 } 219 return (A_DENY); /* No rule is mached. Deny this packet */ 220 } 221 return (A_PERMIT); /* No rule is given. Permit this packet */ 222} 223 224#ifdef notdef 225static void 226IcmpError(struct ip * pip, int code) 227{ 228 struct mbuf *bp; 229 230 if (pip->ip_p != IPPROTO_ICMP) { 231 bp = mbuf_Alloc(cnt, MB_IPIN); 232 memcpy(MBUF_CTOP(bp), ptr, cnt); 233 vj_SendFrame(bp); 234 ipcp_AddOutOctets(cnt); 235 } 236} 237#endif 238 239/* 240 * For debugging aid. 241 */ 242int 243PacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter) 244{ 245 struct ip *pip; 246 struct tcphdr *th; 247 struct udphdr *uh; 248 struct icmp *icmph; 249 char *ptop; 250 int mask, len, n; 251 int pri = PRI_NORMAL; 252 int logit, loglen; 253 char logbuf[200]; 254 255 logit = log_IsKept(LogTCPIP) && filter->logok; 256 loglen = 0; 257 258 pip = (struct ip *) cp; 259 260 if (logit && loglen < sizeof logbuf) { 261 snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name); 262 loglen += strlen(logbuf + loglen); 263 } 264 ptop = (cp + (pip->ip_hl << 2)); 265 266 switch (pip->ip_p) { 267 case IPPROTO_ICMP: 268 if (logit && loglen < sizeof logbuf) { 269 icmph = (struct icmp *) ptop; 270 snprintf(logbuf + loglen, sizeof logbuf - loglen, 271 "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type); 272 loglen += strlen(logbuf + loglen); 273 snprintf(logbuf + loglen, sizeof logbuf - loglen, 274 "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type); 275 loglen += strlen(logbuf + loglen); 276 } 277 break; 278 case IPPROTO_UDP: 279 if (logit && loglen < sizeof logbuf) { 280 uh = (struct udphdr *) ptop; 281 snprintf(logbuf + loglen, sizeof logbuf - loglen, 282 "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 283 loglen += strlen(logbuf + loglen); 284 snprintf(logbuf + loglen, sizeof logbuf - loglen, 285 "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 286 loglen += strlen(logbuf + loglen); 287 } 288 break; 289 case IPPROTO_IPIP: 290 if (logit && loglen < sizeof logbuf) { 291 uh = (struct udphdr *) ptop; 292 snprintf(logbuf + loglen, sizeof logbuf - loglen, 293 "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 294 loglen += strlen(logbuf + loglen); 295 snprintf(logbuf + loglen, sizeof logbuf - loglen, 296 "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 297 loglen += strlen(logbuf + loglen); 298 } 299 break; 300 case IPPROTO_IGMP: 301 if (logit && loglen < sizeof logbuf) { 302 uh = (struct udphdr *) ptop; 303 snprintf(logbuf + loglen, sizeof logbuf - loglen, 304 "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 305 loglen += strlen(logbuf + loglen); 306 snprintf(logbuf + loglen, sizeof logbuf - loglen, 307 "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 308 loglen += strlen(logbuf + loglen); 309 } 310 break; 311 case IPPROTO_TCP: 312 th = (struct tcphdr *) ptop; 313 if (pip->ip_tos == IPTOS_LOWDELAY) 314 pri = PRI_FAST; 315 else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 316 if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport))) 317 pri = PRI_FAST; 318 } 319 if (logit && loglen < sizeof logbuf) { 320 len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2); 321 snprintf(logbuf + loglen, sizeof logbuf - loglen, 322 "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport)); 323 loglen += strlen(logbuf + loglen); 324 snprintf(logbuf + loglen, sizeof logbuf - loglen, 325 "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport)); 326 loglen += strlen(logbuf + loglen); 327 n = 0; 328 for (mask = TH_FIN; mask != 0x40; mask <<= 1) { 329 if (th->th_flags & mask) { 330 snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]); 331 loglen += strlen(logbuf + loglen); 332 } 333 n++; 334 } 335 snprintf(logbuf + loglen, sizeof logbuf - loglen, 336 " seq:%lx ack:%lx (%d/%d)", 337 (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb); 338 loglen += strlen(logbuf + loglen); 339 if ((th->th_flags & TH_SYN) && nb > 40) { 340 u_short *sp; 341 342 ptop += 20; 343 sp = (u_short *) ptop; 344 if (ntohs(sp[0]) == 0x0204) { 345 snprintf(logbuf + loglen, sizeof logbuf - loglen, 346 " MSS = %d", ntohs(sp[1])); 347 loglen += strlen(logbuf + loglen); 348 } 349 } 350 } 351 break; 352 } 353 354 if ((FilterCheck(pip, filter) & A_DENY)) { 355 if (logit) 356 log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf); 357#ifdef notdef 358 if (direction == 0) 359 IcmpError(pip, pri); 360#endif 361 return (-1); 362 } else { 363 /* Check Keep Alive filter */ 364 if (logit) { 365 if (FilterCheck(pip, &bundle->filter.alive) & A_DENY) 366 log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf); 367 else 368 log_Printf(LogTCPIP, "%s\n", logbuf); 369 } 370 return (pri); 371 } 372} 373 374void 375ip_Input(struct bundle *bundle, struct mbuf * bp) 376{ 377 u_char *cp; 378 struct mbuf *wp; 379 int nb, nw; 380 struct tun_data tun; 381 struct ip *pip = (struct ip *)tun.data; 382#ifndef NOALIAS 383 struct ip *piip = (struct ip *)((char *)pip + (pip->ip_hl << 2)); 384#endif 385 386 tun_fill_header(tun, AF_INET); 387 cp = tun.data; 388 nb = 0; 389 for (wp = bp; wp; wp = wp->next) { /* Copy to contiguous region */ 390 if (sizeof tun.data - (cp - tun.data) < wp->cnt) { 391 log_Printf(LogWARN, "ip_Input: Packet too large (%d) - dropped\n", 392 mbuf_Length(bp)); 393 mbuf_Free(bp); 394 return; 395 } 396 memcpy(cp, MBUF_CTOP(wp), wp->cnt); 397 cp += wp->cnt; 398 nb += wp->cnt; 399 } 400 401#ifndef NOALIAS 402 if (bundle->AliasEnabled && pip->ip_p != IPPROTO_IGMP && 403 (pip->ip_p != IPPROTO_IPIP || !IN_CLASSD(ntohl(piip->ip_dst.s_addr)))) { 404 struct tun_data *frag; 405 int iresult; 406 char *fptr; 407 408 iresult = PacketAliasIn(tun.data, sizeof tun.data); 409 nb = ntohs(((struct ip *) tun.data)->ip_len); 410 411 if (nb > MAX_MRU) { 412 log_Printf(LogWARN, "ip_Input: Problem with IP header length\n"); 413 mbuf_Free(bp); 414 return; 415 } 416 if (iresult == PKT_ALIAS_OK 417 || iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 418 if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) { 419 mbuf_Free(bp); 420 return; 421 } 422 423 if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY)) 424 bundle_StartIdleTimer(bundle); 425 426 ipcp_AddInOctets(&bundle->ncp.ipcp, nb); 427 428 nb = ntohs(((struct ip *) tun.data)->ip_len); 429 nb += sizeof tun - sizeof tun.data; 430 nw = write(bundle->dev.fd, &tun, nb); 431 if (nw != nb) { 432 if (nw == -1) 433 log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb, 434 strerror(errno)); 435 else 436 log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw); 437 } 438 439 if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 440 while ((fptr = PacketAliasGetFragment(tun.data)) != NULL) { 441 PacketAliasFragmentIn(tun.data, fptr); 442 nb = ntohs(((struct ip *) fptr)->ip_len); 443 frag = (struct tun_data *) 444 ((char *)fptr - sizeof tun + sizeof tun.data); 445 nb += sizeof tun - sizeof tun.data; 446 nw = write(bundle->dev.fd, frag, nb); 447 if (nw != nb) { 448 if (nw == -1) 449 log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb, 450 strerror(errno)); 451 else 452 log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw); 453 } 454 free(frag); 455 } 456 } 457 } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) { 458 nb = ntohs(((struct ip *) tun.data)->ip_len); 459 nb += sizeof tun - sizeof tun.data; 460 frag = (struct tun_data *)malloc(nb); 461 if (frag == NULL) 462 log_Printf(LogALERT, "ip_Input: Cannot allocate memory for fragment\n"); 463 else { 464 tun_fill_header(*frag, AF_INET); 465 memcpy(frag->data, tun.data, nb - sizeof tun + sizeof tun.data); 466 PacketAliasSaveFragment(frag->data); 467 } 468 } 469 } else 470#endif /* #ifndef NOALIAS */ 471 { /* no aliasing */ 472 if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) { 473 mbuf_Free(bp); 474 return; 475 } 476 477 if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY)) 478 bundle_StartIdleTimer(bundle); 479 480 ipcp_AddInOctets(&bundle->ncp.ipcp, nb); 481 482 nb += sizeof tun - sizeof tun.data; 483 nw = write(bundle->dev.fd, &tun, nb); 484 if (nw != nb) { 485 if (nw == -1) 486 log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb, strerror(errno)); 487 else 488 log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw); 489 } 490 } 491 mbuf_Free(bp); 492} 493 494static struct mqueue IpOutputQueues[PRI_FAST + 1]; 495 496void 497ip_Enqueue(int pri, char *ptr, int count) 498{ 499 struct mbuf *bp; 500 501 bp = mbuf_Alloc(count, MB_IPQ); 502 memcpy(MBUF_CTOP(bp), ptr, count); 503 mbuf_Enqueue(&IpOutputQueues[pri], bp); 504} 505 506int 507ip_QueueLen() 508{ 509 struct mqueue *queue; 510 int result = 0; 511 512 for (queue = &IpOutputQueues[PRI_MAX]; queue >= IpOutputQueues; queue--) 513 result += queue->qlen; 514 515 return result; 516} 517 518int 519ip_FlushPacket(struct link *l, struct bundle *bundle) 520{ 521 struct mqueue *queue; 522 struct mbuf *bp; 523 int cnt; 524 525 if (bundle->ncp.ipcp.fsm.state != ST_OPENED) 526 return 0; 527 528 for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) 529 if (queue->top) { 530 bp = mbuf_Dequeue(queue); 531 if (bp) { 532 struct ip *pip = (struct ip *)MBUF_CTOP(bp); 533 534 cnt = mbuf_Length(bp); 535 if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY)) 536 bundle_StartIdleTimer(bundle); 537 vj_SendFrame(l, bp, bundle); 538 ipcp_AddOutOctets(&bundle->ncp.ipcp, cnt); 539 return 1; 540 } 541 } 542 543 return 0; 544} 545