xref: /freebsd/usr.sbin/ppp/ip.c (revision f9ce010afdd3136fc73e2b500f2ed916bf9cfa59)
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  * $FreeBSD$
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 <string.h>
42 #include <termios.h>
43 #include <unistd.h>
44 
45 #include "layer.h"
46 #include "proto.h"
47 #include "mbuf.h"
48 #include "log.h"
49 #include "defs.h"
50 #include "timer.h"
51 #include "fsm.h"
52 #include "lqr.h"
53 #include "hdlc.h"
54 #include "throughput.h"
55 #include "iplist.h"
56 #include "slcompress.h"
57 #include "ipcp.h"
58 #include "filter.h"
59 #include "descriptor.h"
60 #include "lcp.h"
61 #include "ccp.h"
62 #include "link.h"
63 #include "mp.h"
64 #ifndef NORADIUS
65 #include "radius.h"
66 #endif
67 #include "bundle.h"
68 #include "tun.h"
69 #include "ip.h"
70 
71 static const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" };
72 
73 static __inline int
74 PortMatch(int op, u_short pport, u_short rport)
75 {
76   switch (op) {
77   case OP_EQ:
78     return (pport == rport);
79   case OP_GT:
80     return (pport > rport);
81   case OP_LT:
82     return (pport < rport);
83   default:
84     return (0);
85   }
86 }
87 
88 /*
89  *  Check a packet against a defined filter
90  *  Returns 0 to accept the packet, non-zero to drop the packet
91  *
92  *  If filtering is enabled, the initial fragment of a datagram must
93  *  contain the complete protocol header, and subsequent fragments
94  *  must not attempt to over-write it.
95  */
96 static int
97 FilterCheck(const struct ip *pip, const struct filter *filter)
98 {
99   int gotinfo;			/* true if IP payload decoded */
100   int cproto;			/* P_* protocol type if (gotinfo) */
101   int estab, syn, finrst;	/* TCP state flags if (gotinfo) */
102   u_short sport, dport;		/* src, dest port from packet if (gotinfo) */
103   int n;			/* filter rule to process */
104   int len;			/* bytes used in dbuff */
105   int didname;			/* true if filter header printed */
106   int match;			/* true if condition matched */
107   const struct filterent *fp = filter->rule;
108   char dbuff[100];
109 
110   if (fp->f_action == A_NONE)
111     return (0);		/* No rule is given. Permit this packet */
112 
113   /* Deny any packet fragment that tries to over-write the header.
114    * Since we no longer have the real header available, punt on the
115    * largest normal header - 20 bytes for TCP without options, rounded
116    * up to the next possible fragment boundary.  Since the smallest
117    * `legal' MTU is 576, and the smallest recommended MTU is 296, any
118    * fragmentation within this range is dubious at best */
119   len = ntohs(pip->ip_off) & IP_OFFMASK;	/* fragment offset */
120   if (len > 0) {		/* Not first fragment within datagram */
121     if (len < (24 >> 3))	/* don't allow fragment to over-write header */
122       return (1);
123     /* permit fragments on in and out filter */
124     return (filter->fragok);
125   }
126 
127   cproto = gotinfo = estab = syn = finrst = didname = 0;
128   sport = dport = 0;
129   for (n = 0; n < MAXFILTERS; ) {
130     if (fp->f_action == A_NONE) {
131       n++;
132       fp++;
133       continue;
134     }
135 
136     if (!didname) {
137       log_Printf(LogDEBUG, "%s filter:\n", filter->name);
138       didname = 1;
139     }
140 
141     match = 0;
142     if (!((pip->ip_src.s_addr ^ fp->f_src.ipaddr.s_addr) &
143 	  fp->f_src.mask.s_addr) &&
144 	!((pip->ip_dst.s_addr ^ fp->f_dst.ipaddr.s_addr) &
145 	  fp->f_dst.mask.s_addr)) {
146       if (fp->f_proto != P_NONE) {
147 	if (!gotinfo) {
148 	  const char *ptop = (const char *) pip + (pip->ip_hl << 2);
149 	  const struct tcphdr *th;
150 	  const struct udphdr *uh;
151 	  const struct icmp *ih;
152 	  int datalen;	/* IP datagram length */
153 
154 	  datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
155 	  switch (pip->ip_p) {
156 	  case IPPROTO_ICMP:
157 	    cproto = P_ICMP;
158 	    if (datalen < 8)	/* ICMP must be at least 8 octets */
159 	      return (1);
160 	    ih = (const struct icmp *) ptop;
161 	    sport = ih->icmp_type;
162 	    estab = syn = finrst = -1;
163 	    if (log_IsKept(LogDEBUG))
164 	      snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
165 	    break;
166 	  case IPPROTO_IGMP:
167 	    cproto = P_IGMP;
168 	    if (datalen < 8)	/* IGMP uses 8-octet messages */
169 	      return (1);
170 	    estab = syn = finrst = -1;
171 	    sport = ntohs(0);
172 	    break;
173 #ifdef IPPROTO_OSPFIGP
174 	  case IPPROTO_OSPFIGP:
175 	    cproto = P_OSPF;
176 	    if (datalen < 8)	/* IGMP uses 8-octet messages */
177 	      return (1);
178 	    estab = syn = finrst = -1;
179 	    sport = ntohs(0);
180 	    break;
181 #endif
182 	  case IPPROTO_UDP:
183 	  case IPPROTO_IPIP:
184 	    cproto = P_UDP;
185 	    if (datalen < 8)	/* UDP header is 8 octets */
186 	      return (1);
187 	    uh = (const struct udphdr *) ptop;
188 	    sport = ntohs(uh->uh_sport);
189 	    dport = ntohs(uh->uh_dport);
190 	    estab = syn = finrst = -1;
191 	    if (log_IsKept(LogDEBUG))
192 	      snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
193 		       sport, dport);
194 	    break;
195 	  case IPPROTO_TCP:
196 	    cproto = P_TCP;
197 	    th = (const struct tcphdr *) ptop;
198 	    /* TCP headers are variable length.  The following code
199 	     * ensures that the TCP header length isn't de-referenced if
200 	     * the datagram is too short
201 	     */
202 	    if (datalen < 20 || datalen < (th->th_off << 2))
203 	      return (1);
204 	    sport = ntohs(th->th_sport);
205 	    dport = ntohs(th->th_dport);
206 	    estab = (th->th_flags & TH_ACK);
207 	    syn = (th->th_flags & TH_SYN);
208 	    finrst = (th->th_flags & (TH_FIN|TH_RST));
209 	    if (log_IsKept(LogDEBUG)) {
210 	      if (!estab)
211 		snprintf(dbuff, sizeof dbuff,
212 			 "flags = %02x, sport = %d, dport = %d",
213 			 th->th_flags, sport, dport);
214 	      else
215 		*dbuff = '\0';
216 	    }
217 	    break;
218 	  default:
219 	    return (1);	/* We'll block unknown type of packet */
220 	  }
221 
222 	  if (log_IsKept(LogDEBUG)) {
223 	    if (estab != -1) {
224 	      len = strlen(dbuff);
225 	      snprintf(dbuff + len, sizeof dbuff - len,
226 		       ", estab = %d, syn = %d, finrst = %d",
227 		       estab, syn, finrst);
228 	    }
229 	    log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
230 		       filter_Proto2Nam(cproto), dbuff);
231 	  }
232 	  gotinfo = 1;
233 	}
234 	if (log_IsKept(LogDEBUG)) {
235 	  if (fp->f_srcop != OP_NONE) {
236 	    snprintf(dbuff, sizeof dbuff, ", src %s %d",
237 		     filter_Op2Nam(fp->f_srcop), fp->f_srcport);
238 	    len = strlen(dbuff);
239 	  } else
240 	    len = 0;
241 	  if (fp->f_dstop != OP_NONE) {
242 	    snprintf(dbuff + len, sizeof dbuff - len,
243 		     ", dst %s %d", filter_Op2Nam(fp->f_dstop),
244 		     fp->f_dstport);
245 	  } else if (!len)
246 	    *dbuff = '\0';
247 
248 	  log_Printf(LogDEBUG, "  rule = %d: Address match, "
249 		     "check against proto %s%s, action = %s\n",
250 		     n, filter_Proto2Nam(fp->f_proto),
251 		     dbuff, filter_Action2Nam(fp->f_action));
252 	}
253 
254 	if (cproto == fp->f_proto) {
255 	  if ((fp->f_srcop == OP_NONE ||
256 	       PortMatch(fp->f_srcop, sport, fp->f_srcport)) &&
257 	      (fp->f_dstop == OP_NONE ||
258 	       PortMatch(fp->f_dstop, dport, fp->f_dstport)) &&
259 	      (fp->f_estab == 0 || estab) &&
260 	      (fp->f_syn == 0 || syn) &&
261 	      (fp->f_finrst == 0 || finrst)) {
262 	    match = 1;
263 	  }
264 	}
265       } else {
266 	/* Address is matched and no protocol specified. Make a decision. */
267 	log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
268 		   filter_Action2Nam(fp->f_action));
269 	match = 1;
270       }
271     } else
272       log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
273 
274     if (match != fp->f_invert) {
275       /* Take specified action */
276       if (fp->f_action < A_NONE)
277 	fp = &filter->rule[n = fp->f_action];
278       else
279 	return (fp->f_action != A_PERMIT);
280     } else {
281       n++;
282       fp++;
283     }
284   }
285   return (1);		/* No rule is mached. Deny this packet */
286 }
287 
288 #ifdef notdef
289 static void
290 IcmpError(struct ip *pip, int code)
291 {
292   struct mbuf *bp;
293 
294   if (pip->ip_p != IPPROTO_ICMP) {
295     bp = mbuf_Alloc(cnt, MB_IPIN);
296     memcpy(MBUF_CTOP(bp), ptr, cnt);
297     vj_SendFrame(bp);
298     ipcp_AddOutOctets(cnt);
299   }
300 }
301 #endif
302 
303 /*
304  *  For debugging aid.
305  */
306 int
307 PacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter)
308 {
309   struct ip *pip;
310   struct tcphdr *th;
311   struct udphdr *uh;
312   struct icmp *icmph;
313   char *ptop;
314   int mask, len, n;
315   int pri = 0;
316   int logit, loglen;
317   char logbuf[200];
318 
319   logit = log_IsKept(LogTCPIP) && filter->logok;
320   loglen = 0;
321 
322   pip = (struct ip *) cp;
323 
324   if (logit && loglen < sizeof logbuf) {
325     snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
326     loglen += strlen(logbuf + loglen);
327   }
328   ptop = (cp + (pip->ip_hl << 2));
329 
330   switch (pip->ip_p) {
331   case IPPROTO_ICMP:
332     if (logit && loglen < sizeof logbuf) {
333       icmph = (struct icmp *) ptop;
334       snprintf(logbuf + loglen, sizeof logbuf - loglen,
335 	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
336       loglen += strlen(logbuf + loglen);
337       snprintf(logbuf + loglen, sizeof logbuf - loglen,
338 	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
339       loglen += strlen(logbuf + loglen);
340     }
341     break;
342   case IPPROTO_UDP:
343     if (logit && loglen < sizeof logbuf) {
344       uh = (struct udphdr *) ptop;
345       snprintf(logbuf + loglen, sizeof logbuf - loglen,
346 	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
347       loglen += strlen(logbuf + loglen);
348       snprintf(logbuf + loglen, sizeof logbuf - loglen,
349 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
350       loglen += strlen(logbuf + loglen);
351     }
352     break;
353 #ifdef IPPROTO_OSPFIGP
354   case IPPROTO_OSPFIGP:
355     if (logit && loglen < sizeof logbuf) {
356       snprintf(logbuf + loglen, sizeof logbuf - loglen,
357 	   "OSPF: %s ---> ", inet_ntoa(pip->ip_src));
358       loglen += strlen(logbuf + loglen);
359       snprintf(logbuf + loglen, sizeof logbuf - loglen,
360 	       "%s", inet_ntoa(pip->ip_dst));
361       loglen += strlen(logbuf + loglen);
362     }
363     break;
364 #endif
365   case IPPROTO_IPIP:
366     if (logit && loglen < sizeof logbuf) {
367       uh = (struct udphdr *) ptop;
368       snprintf(logbuf + loglen, sizeof logbuf - loglen,
369 	   "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
370       loglen += strlen(logbuf + loglen);
371       snprintf(logbuf + loglen, sizeof logbuf - loglen,
372 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
373       loglen += strlen(logbuf + loglen);
374     }
375     break;
376   case IPPROTO_IGMP:
377     if (logit && loglen < sizeof logbuf) {
378       uh = (struct udphdr *) ptop;
379       snprintf(logbuf + loglen, sizeof logbuf - loglen,
380 	   "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
381       loglen += strlen(logbuf + loglen);
382       snprintf(logbuf + loglen, sizeof logbuf - loglen,
383 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
384       loglen += strlen(logbuf + loglen);
385     }
386     break;
387   case IPPROTO_TCP:
388     th = (struct tcphdr *) ptop;
389     if (pip->ip_tos == IPTOS_LOWDELAY)
390       pri++;
391     else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
392              ipcp_IsUrgentPort(&bundle->ncp.ipcp, ntohs(th->th_sport),
393                                ntohs(th->th_dport)))
394       pri++;
395 
396     if (logit && loglen < sizeof logbuf) {
397       len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
398       snprintf(logbuf + loglen, sizeof logbuf - loglen,
399 	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
400       loglen += strlen(logbuf + loglen);
401       snprintf(logbuf + loglen, sizeof logbuf - loglen,
402 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
403       loglen += strlen(logbuf + loglen);
404       n = 0;
405       for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
406 	if (th->th_flags & mask) {
407 	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
408 	  loglen += strlen(logbuf + loglen);
409 	}
410 	n++;
411       }
412       snprintf(logbuf + loglen, sizeof logbuf - loglen,
413 	       "  seq:%lx  ack:%lx (%d/%d)",
414 	       (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
415       loglen += strlen(logbuf + loglen);
416       if ((th->th_flags & TH_SYN) && nb > 40) {
417 	u_short *sp;
418 
419 	ptop += 20;
420 	sp = (u_short *) ptop;
421 	if (ntohs(sp[0]) == 0x0204) {
422 	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
423 		   " MSS = %d", ntohs(sp[1]));
424 	  loglen += strlen(logbuf + loglen);
425 	}
426       }
427     }
428     break;
429   }
430 
431   if (FilterCheck(pip, filter)) {
432     if (logit)
433       log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
434 #ifdef notdef
435     if (direction == 0)
436       IcmpError(pip, pri);
437 #endif
438     return (-1);
439   } else {
440     /* Check Keep Alive filter */
441     if (logit) {
442       if (FilterCheck(pip, &bundle->filter.alive))
443         log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
444       else
445         log_Printf(LogTCPIP, "%s\n", logbuf);
446     }
447     return (pri);
448   }
449 }
450 
451 struct mbuf *
452 ip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
453 {
454   int nb, nw;
455   struct tun_data tun;
456   struct ip *pip;
457 
458   if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
459     log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n");
460     mbuf_Free(bp);
461     return NULL;
462   }
463 
464   mbuf_SetType(bp, MB_IPIN);
465   tun_fill_header(tun, AF_INET);
466   nb = mbuf_Length(bp);
467   if (nb > sizeof tun.data) {
468     log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n",
469                l->name, nb, (int)(sizeof tun.data));
470     mbuf_Free(bp);
471     return NULL;
472   }
473   mbuf_Read(bp, tun.data, nb);
474 
475   if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0)
476     return NULL;
477 
478   pip = (struct ip *)tun.data;
479   if (!FilterCheck(pip, &bundle->filter.alive))
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: %s: wrote %d, got %s\n",
489                  l->name, nb, strerror(errno));
490     else
491       log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw);
492   }
493 
494   return NULL;
495 }
496 
497 void
498 ip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count)
499 {
500   struct mbuf *bp;
501 
502   if (pri < 0 || pri >= IPCP_QUEUES(ipcp))
503     log_Printf(LogERROR, "Can't store in ip queue %d\n", pri);
504   else {
505     /*
506      * We allocate an extra 6 bytes, four at the front and two at the end.
507      * This is an optimisation so that we need to do less work in
508      * mbuf_Prepend() in acf_LayerPush() and proto_LayerPush() and
509      * appending in hdlc_LayerPush().
510      */
511     bp = mbuf_Alloc(count + 6, MB_IPOUT);
512     bp->offset += 4;
513     bp->cnt -= 6;
514     memcpy(MBUF_CTOP(bp), ptr, count);
515     mbuf_Enqueue(ipcp->Queue + pri, bp);
516   }
517 }
518 
519 void
520 ip_DeleteQueue(struct ipcp *ipcp)
521 {
522   struct mqueue *queue;
523 
524   for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
525     while (queue->top)
526       mbuf_Free(mbuf_Dequeue(queue));
527 }
528 
529 int
530 ip_QueueLen(struct ipcp *ipcp)
531 {
532   struct mqueue *queue;
533   int result = 0;
534 
535   for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
536     result += queue->qlen;
537 
538   return result;
539 }
540 
541 int
542 ip_PushPacket(struct link *l, struct bundle *bundle)
543 {
544   struct ipcp *ipcp = &bundle->ncp.ipcp;
545   struct mqueue *queue;
546   struct mbuf *bp;
547   struct ip *pip;
548   int cnt;
549 
550   if (ipcp->fsm.state != ST_OPENED)
551     return 0;
552 
553   queue = ipcp->Queue + IPCP_QUEUES(ipcp) - 1;
554   do {
555     if (queue->top) {
556       bp = mbuf_Contiguous(mbuf_Dequeue(queue));
557       cnt = mbuf_Length(bp);
558       pip = (struct ip *)MBUF_CTOP(bp);
559       if (!FilterCheck(pip, &bundle->filter.alive))
560         bundle_StartIdleTimer(bundle);
561       link_PushPacket(l, bp, bundle, 0, PROTO_IP);
562       ipcp_AddOutOctets(ipcp, cnt);
563       return 1;
564     }
565   } while (queue-- != ipcp->Queue);
566 
567   return 0;
568 }
569