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