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