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