ip.c revision 46828
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.59 1999/05/08 11:06:42 brian Exp $ 21 * 22 * TODO: 23 * o Return ICMP message for filterd packet 24 * and optionaly record it into log. 25 */ 26#include <sys/param.h> 27#if defined(__OpenBSD__) || defined(__NetBSD__) 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 <termios.h> 44#include <unistd.h> 45 46#include "layer.h" 47#include "proto.h" 48#include "mbuf.h" 49#include "log.h" 50#include "defs.h" 51#include "timer.h" 52#include "fsm.h" 53#include "lqr.h" 54#include "hdlc.h" 55#include "throughput.h" 56#include "iplist.h" 57#include "slcompress.h" 58#include "ipcp.h" 59#include "filter.h" 60#include "descriptor.h" 61#include "lcp.h" 62#include "ccp.h" 63#include "link.h" 64#include "mp.h" 65#ifndef NORADIUS 66#include "radius.h" 67#endif 68#include "bundle.h" 69#include "vjcomp.h" 70#include "tun.h" 71#include "ip.h" 72 73static const u_short interactive_ports[32] = { 74 544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75 80, 81, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543, 76}; 77 78#define INTERACTIVE(p) (interactive_ports[(p) & 0x1F] == (p)) 79 80static const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" }; 81 82static int 83PortMatch(int op, u_short pport, u_short rport) 84{ 85 switch (op) { 86 case OP_EQ: 87 return (pport == rport); 88 case OP_GT: 89 return (pport > rport); 90 case OP_LT: 91 return (pport < rport); 92 default: 93 return (0); 94 } 95} 96 97/* 98 * Check a packet against a defined filter 99 */ 100static int 101FilterCheck(struct ip *pip, struct filter *filter) 102{ 103 int gotinfo, cproto, estab, syn, finrst, n, len, didname; 104 struct tcphdr *th; 105 struct udphdr *uh; 106 struct icmp *ih; 107 char *ptop; 108 u_short sport, dport; 109 struct filterent *fp = filter->rule; 110 char dbuff[100]; 111 112 if (fp->action) { 113 cproto = gotinfo = estab = syn = finrst = didname = 0; 114 sport = dport = 0; 115 for (n = 0; n < MAXFILTERS; n++) { 116 if (fp->action) { 117 /* permit fragments on in and out filter */ 118 if (filter->fragok && (ntohs(pip->ip_off) & IP_OFFMASK) != 0) 119 return (A_PERMIT); 120 121 if (!didname) 122 log_Printf(LogDEBUG, "%s filter:\n", filter->name); 123 didname = 1; 124 125 if ((pip->ip_src.s_addr & fp->smask.s_addr) == 126 (fp->saddr.s_addr & fp->smask.s_addr) && 127 (pip->ip_dst.s_addr & fp->dmask.s_addr) == 128 (fp->daddr.s_addr & fp->dmask.s_addr)) { 129 if (fp->proto) { 130 if (!gotinfo) { 131 ptop = (char *) pip + (pip->ip_hl << 2); 132 133 switch (pip->ip_p) { 134 case IPPROTO_ICMP: 135 cproto = P_ICMP; 136 ih = (struct icmp *) ptop; 137 sport = ih->icmp_type; 138 estab = syn = finrst = -1; 139 if (log_IsKept(LogDEBUG)) 140 snprintf(dbuff, sizeof dbuff, "sport = %d", sport); 141 break; 142 case IPPROTO_UDP: 143 case IPPROTO_IGMP: 144 case IPPROTO_IPIP: 145 cproto = P_UDP; 146 uh = (struct udphdr *) ptop; 147 sport = ntohs(uh->uh_sport); 148 dport = ntohs(uh->uh_dport); 149 estab = syn = finrst = -1; 150 if (log_IsKept(LogDEBUG)) 151 snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d", 152 sport, dport); 153 break; 154 case IPPROTO_TCP: 155 cproto = P_TCP; 156 th = (struct tcphdr *) ptop; 157 sport = ntohs(th->th_sport); 158 dport = ntohs(th->th_dport); 159 estab = (th->th_flags & TH_ACK); 160 syn = (th->th_flags & TH_SYN); 161 finrst = (th->th_flags & (TH_FIN|TH_RST)); 162 if (log_IsKept(LogDEBUG)) { 163 if (!estab) 164 snprintf(dbuff, sizeof dbuff, 165 "flags = %02x, sport = %d, dport = %d", 166 th->th_flags, sport, dport); 167 else 168 *dbuff = '\0'; 169 } 170 break; 171 default: 172 return (A_DENY); /* We'll block unknown type of packet */ 173 } 174 if (log_IsKept(LogDEBUG)) { 175 if (estab != -1) { 176 len = strlen(dbuff); 177 snprintf(dbuff + len, sizeof dbuff - len, 178 ", estab = %d, syn = %d, finrst = %d", 179 estab, syn, finrst); 180 } 181 log_Printf(LogDEBUG, " Filter: proto = %s, %s\n", 182 filter_Proto2Nam(cproto), dbuff); 183 } 184 gotinfo = 1; 185 } 186 if (log_IsKept(LogDEBUG)) { 187 if (fp->opt.srcop != OP_NONE) { 188 snprintf(dbuff, sizeof dbuff, ", src %s %d", 189 filter_Op2Nam(fp->opt.srcop), fp->opt.srcport); 190 len = strlen(dbuff); 191 } else 192 len = 0; 193 if (fp->opt.dstop != OP_NONE) { 194 snprintf(dbuff + len, sizeof dbuff - len, 195 ", dst %s %d", filter_Op2Nam(fp->opt.dstop), 196 fp->opt.dstport); 197 } else if (!len) 198 *dbuff = '\0'; 199 200 log_Printf(LogDEBUG, " rule = %d: Address match, " 201 "check against proto %s%s, action = %s\n", 202 n, filter_Proto2Nam(fp->proto), 203 dbuff, filter_Action2Nam(fp->action)); 204 } 205 206 if (cproto == fp->proto) { 207 if ((fp->opt.srcop == OP_NONE || 208 PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) && 209 (fp->opt.dstop == OP_NONE || 210 PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) && 211 (fp->opt.estab == 0 || estab) && 212 (fp->opt.syn == 0 || syn) && 213 (fp->opt.finrst == 0 || finrst)) { 214 return (fp->action); 215 } 216 } 217 } else { 218 /* Address is mached. Make a decision. */ 219 log_Printf(LogDEBUG, " rule = %d: Address match, action = %s\n", n, 220 filter_Action2Nam(fp->action)); 221 return (fp->action); 222 } 223 } else 224 log_Printf(LogDEBUG, " rule = %d: Address mismatch\n", n); 225 } 226 fp++; 227 } 228 return (A_DENY); /* No rule is mached. Deny this packet */ 229 } 230 return (A_PERMIT); /* No rule is given. Permit this packet */ 231} 232 233#ifdef notdef 234static void 235IcmpError(struct ip *pip, int code) 236{ 237 struct mbuf *bp; 238 239 if (pip->ip_p != IPPROTO_ICMP) { 240 bp = mbuf_Alloc(cnt, MB_IPIN); 241 memcpy(MBUF_CTOP(bp), ptr, cnt); 242 vj_SendFrame(bp); 243 ipcp_AddOutOctets(cnt); 244 } 245} 246#endif 247 248/* 249 * For debugging aid. 250 */ 251int 252PacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter) 253{ 254 struct ip *pip; 255 struct tcphdr *th; 256 struct udphdr *uh; 257 struct icmp *icmph; 258 char *ptop; 259 int mask, len, n; 260 int pri = PRI_NORMAL; 261 int logit, loglen; 262 char logbuf[200]; 263 264 logit = log_IsKept(LogTCPIP) && filter->logok; 265 loglen = 0; 266 267 pip = (struct ip *) cp; 268 269 if (logit && loglen < sizeof logbuf) { 270 snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name); 271 loglen += strlen(logbuf + loglen); 272 } 273 ptop = (cp + (pip->ip_hl << 2)); 274 275 switch (pip->ip_p) { 276 case IPPROTO_ICMP: 277 if (logit && loglen < sizeof logbuf) { 278 icmph = (struct icmp *) ptop; 279 snprintf(logbuf + loglen, sizeof logbuf - loglen, 280 "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type); 281 loglen += strlen(logbuf + loglen); 282 snprintf(logbuf + loglen, sizeof logbuf - loglen, 283 "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type); 284 loglen += strlen(logbuf + loglen); 285 } 286 break; 287 case IPPROTO_UDP: 288 if (logit && loglen < sizeof logbuf) { 289 uh = (struct udphdr *) ptop; 290 snprintf(logbuf + loglen, sizeof logbuf - loglen, 291 "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 292 loglen += strlen(logbuf + loglen); 293 snprintf(logbuf + loglen, sizeof logbuf - loglen, 294 "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 295 loglen += strlen(logbuf + loglen); 296 } 297 break; 298 case IPPROTO_IPIP: 299 if (logit && loglen < sizeof logbuf) { 300 uh = (struct udphdr *) ptop; 301 snprintf(logbuf + loglen, sizeof logbuf - loglen, 302 "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 303 loglen += strlen(logbuf + loglen); 304 snprintf(logbuf + loglen, sizeof logbuf - loglen, 305 "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 306 loglen += strlen(logbuf + loglen); 307 } 308 break; 309 case IPPROTO_IGMP: 310 if (logit && loglen < sizeof logbuf) { 311 uh = (struct udphdr *) ptop; 312 snprintf(logbuf + loglen, sizeof logbuf - loglen, 313 "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 314 loglen += strlen(logbuf + loglen); 315 snprintf(logbuf + loglen, sizeof logbuf - loglen, 316 "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 317 loglen += strlen(logbuf + loglen); 318 } 319 break; 320 case IPPROTO_TCP: 321 th = (struct tcphdr *) ptop; 322 if (pip->ip_tos == IPTOS_LOWDELAY) 323 pri = PRI_FAST; 324 else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 325 if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport))) 326 pri = PRI_FAST; 327 } 328 if (logit && loglen < sizeof logbuf) { 329 len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2); 330 snprintf(logbuf + loglen, sizeof logbuf - loglen, 331 "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport)); 332 loglen += strlen(logbuf + loglen); 333 snprintf(logbuf + loglen, sizeof logbuf - loglen, 334 "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport)); 335 loglen += strlen(logbuf + loglen); 336 n = 0; 337 for (mask = TH_FIN; mask != 0x40; mask <<= 1) { 338 if (th->th_flags & mask) { 339 snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]); 340 loglen += strlen(logbuf + loglen); 341 } 342 n++; 343 } 344 snprintf(logbuf + loglen, sizeof logbuf - loglen, 345 " seq:%lx ack:%lx (%d/%d)", 346 (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb); 347 loglen += strlen(logbuf + loglen); 348 if ((th->th_flags & TH_SYN) && nb > 40) { 349 u_short *sp; 350 351 ptop += 20; 352 sp = (u_short *) ptop; 353 if (ntohs(sp[0]) == 0x0204) { 354 snprintf(logbuf + loglen, sizeof logbuf - loglen, 355 " MSS = %d", ntohs(sp[1])); 356 loglen += strlen(logbuf + loglen); 357 } 358 } 359 } 360 break; 361 } 362 363 if ((FilterCheck(pip, filter) & A_DENY)) { 364 if (logit) 365 log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf); 366#ifdef notdef 367 if (direction == 0) 368 IcmpError(pip, pri); 369#endif 370 return (-1); 371 } else { 372 /* Check Keep Alive filter */ 373 if (logit) { 374 if (FilterCheck(pip, &bundle->filter.alive) & A_DENY) 375 log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf); 376 else 377 log_Printf(LogTCPIP, "%s\n", logbuf); 378 } 379 return (pri); 380 } 381} 382 383struct mbuf * 384ip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 385{ 386 int nb, nw; 387 struct tun_data tun; 388 struct ip *pip; 389 390 if (bundle->ncp.ipcp.fsm.state != ST_OPENED) { 391 log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n"); 392 mbuf_Free(bp); 393 return NULL; 394 } 395 396 tun_fill_header(tun, AF_INET); 397 nb = mbuf_Length(bp); 398 mbuf_Read(bp, tun.data, nb); 399 400 if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) 401 return NULL; 402 403 pip = (struct ip *)tun.data; 404 if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY)) 405 bundle_StartIdleTimer(bundle); 406 407 ipcp_AddInOctets(&bundle->ncp.ipcp, nb); 408 409 nb += sizeof tun - sizeof tun.data; 410 nw = write(bundle->dev.fd, &tun, nb); 411 if (nw != nb) { 412 if (nw == -1) 413 log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb, strerror(errno)); 414 else 415 log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw); 416 } 417 418 return NULL; 419} 420 421void 422ip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count) 423{ 424 struct mbuf *bp; 425 426 if (pri < 0 || pri > sizeof ipcp->Queue / sizeof ipcp->Queue[0]) 427 log_Printf(LogERROR, "Can't store in ip queue %d\n", pri); 428 else { 429 /* 430 * We allocate an extra 6 bytes, four at the front and two at the end. 431 * This is an optimisation so that we need to do less work in 432 * mbuf_Prepend() in acf_LayerPush() and proto_LayerPush() and 433 * appending in hdlc_LayerPush(). 434 */ 435 bp = mbuf_Alloc(count + 6, MB_IPQ); 436 bp->offset += 4; 437 bp->cnt -= 6; 438 memcpy(MBUF_CTOP(bp), ptr, count); 439 mbuf_Enqueue(&ipcp->Queue[pri], bp); 440 } 441} 442 443void 444ip_DeleteQueue(struct ipcp *ipcp) 445{ 446 struct mqueue *queue; 447 448 for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++) 449 while (queue->top) 450 mbuf_Free(mbuf_Dequeue(queue)); 451} 452 453int 454ip_QueueLen(struct ipcp *ipcp) 455{ 456 struct mqueue *queue; 457 int result = 0; 458 459 for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++) 460 result += queue->qlen; 461 462 return result; 463} 464 465int 466ip_PushPacket(struct link *l, struct bundle *bundle) 467{ 468 struct ipcp *ipcp = &bundle->ncp.ipcp; 469 struct mqueue *queue; 470 struct mbuf *bp; 471 struct ip *pip; 472 int cnt; 473 474 if (ipcp->fsm.state != ST_OPENED) 475 return 0; 476 477 for (queue = &ipcp->Queue[PRI_FAST]; queue >= ipcp->Queue; queue--) 478 if (queue->top) { 479 bp = mbuf_Contiguous(mbuf_Dequeue(queue)); 480 cnt = mbuf_Length(bp); 481 pip = (struct ip *)MBUF_CTOP(bp); 482 if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY)) 483 bundle_StartIdleTimer(bundle); 484 link_PushPacket(l, bp, bundle, PRI_NORMAL, PROTO_IP); 485 ipcp_AddOutOctets(ipcp, cnt); 486 return 1; 487 } 488 489 return 0; 490} 491