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