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