xref: /freebsd/usr.sbin/ppp/ip.c (revision 380a989b3223d455375b4fae70fd0b9bdd43bafb)
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 
74 static 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 
81 static const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" };
82 
83 static int
84 PortMatch(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  */
101 static int
102 FilterCheck(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
235 static void
236 IcmpError(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  */
252 int
253 PacketCheck(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 
384 void
385 ip_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 
504 void
505 ip_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 
518 void
519 ip_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 
528 int
529 ip_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 
540 int
541 ip_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