1 /*
2  * Copyright (c) 2003 Niels Provos <provos@citi.umich.edu>
3  * All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  * This program is free software; you can redistribute it and/or modify
19  * it under the terms of the GNU General Public License as published by
20  * the Free Software Foundation; either version 2 of the License, or
21  * (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  * GNU General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License
29  * along with this program; if not, write to the Free Software
30  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
31  */
32 
33 #include <sys/types.h>
34 #include <sys/param.h>
35 
36 #include "config.h"
37 
38 #include <sys/queue.h>
39 #include <sys/tree.h>
40 #ifdef HAVE_SYS_TIME_H
41 #include <sys/time.h>
42 #endif
43 
44 #include <err.h>
45 #include <errno.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50 #include <ctype.h>
51 #include <syslog.h>
52 
53 #include <dnet.h>
54 
55 #undef timeout_pending
56 #undef timeout_initialized
57 
58 #include <event.h>
59 
60 #include "honeyd.h"
61 #include "gre.h"
62 
63 extern rand_t *honeyd_rand;
64 extern int honeyd_ttl;
65 
66 static u_char pkt[IP_LEN_MAX];
67 
68 
69 int
gre_decapsulate(struct ip_hdr * oip,u_short oiplen,struct ip_hdr ** pip,u_short * piplen)70 gre_decapsulate(struct ip_hdr *oip, u_short oiplen,
71     struct ip_hdr **pip, u_short *piplen)
72 {
73 	struct gre_hdr *gre;
74 	struct ip_hdr *ip;
75 	u_char *end = (u_char *)oip + oiplen;
76 	u_char *data;
77 	uint16_t flags, proto, iplen;
78 
79 	gre = (struct gre_hdr *)((u_char *)oip + (oip->ip_hl << 2));
80 	data = (u_char *)(gre + 1);
81 
82 	if (end <= data)
83 		return (-1);
84 
85 	/* We support only RFC 2784 */
86 	flags = ntohs(gre->gre_flags);
87 	if ((flags & ~GRE_CHECKSUM) != 0) {
88 		syslog(LOG_DEBUG,
89 		    "%s: dropping RFC 1701 encapsulation: flags = %x",
90 		    __func__, flags);
91 		return (-1);
92 	}
93 
94 	proto = ntohs(gre->gre_proto);
95 	if (proto != GRE_IP4PROTO) {
96 		syslog(LOG_DEBUG,
97 		    "%s: dropping encapsulated packet: bad protocol %d",
98 		    __func__, proto);
99 		return (-1);
100 	}
101 
102 	if (!(flags & GRE_CHECKSUM))
103 		data = GRE_NOCKSUM_DATA(gre);
104 
105 	/* Check for the proper length of the packet */
106 	ip = (struct ip_hdr *)data;
107 	if (data + sizeof(struct ip_hdr) > end)
108 		return (-1);
109 
110 	iplen = ntohs(ip->ip_len);
111 	if (data + iplen > end)
112 		return (-1);
113 
114 	if (flags & GRE_CHECKSUM) {
115 		u_int sum = gre->gre_sum, tmp;
116 		gre->gre_sum = 0;
117 
118 		tmp = ip_cksum_add(gre, sizeof(struct gre_hdr) + iplen, 0);
119 		tmp = ip_cksum_carry(tmp);
120 		if (sum != tmp) {
121 			syslog(LOG_INFO,
122 			    "%s: dropping encapsulated packet: bad checksum: %x vs %x",
123 			    __func__, ntohs(sum), ntohs(tmp));
124 			return (-1);
125 		}
126 	}
127 
128 	*pip = ip;
129 	*piplen = iplen;
130 
131 	return (0);
132 }
133 
134 int
gre_encapsulate(ip_t * honeyd_ip,struct addr * src,struct addr * dst,struct ip_hdr * iip,u_int iiplen)135 gre_encapsulate(ip_t *honeyd_ip, struct addr *src, struct addr *dst,
136     struct ip_hdr *iip, u_int iiplen)
137 {
138 	struct ip_hdr *oip = (struct ip_hdr *)pkt;
139 	struct gre_hdr *gre = (struct gre_hdr *)(oip + 1);
140 	u_char *data = (u_char *)(gre + 1);
141 	u_int iplen, sum;
142 
143 	iplen = sizeof(struct ip_hdr) + sizeof(struct gre_hdr) + iiplen;
144 
145 	if (iplen > sizeof(pkt)) {
146 		syslog(LOG_ERR, "%s: packet too long: %d", __func__, iplen);
147 		return (-1);
148 	}
149 
150 	ip_pack_hdr(pkt, 0, iplen, rand_uint16(honeyd_rand),
151 	    0, honeyd_ttl, IP_PROTO_GRE, src->addr_ip, dst->addr_ip);
152 
153 	memset(gre, 0, sizeof(struct gre_hdr));
154 	gre->gre_flags = htons(GRE_CHECKSUM | GRE_VERSION);
155 	gre->gre_proto = htons(GRE_IP4PROTO);
156 
157 	/* Copy the payload */
158 	memcpy(data, iip, iiplen);
159 
160 	/* Calculate the checksum */
161 	sum = ip_cksum_add(gre, iiplen + sizeof(struct gre_hdr), 0);
162 	gre->gre_sum = ip_cksum_carry(sum);
163 
164 	ip_checksum(oip, iplen);
165 
166 	return (ip_send(honeyd_ip, pkt, iplen) != iplen ? -1 : 0);
167 }
168