1 /* Copyright 2008 Bernhard R. Fischer, Daniel Haslinger.
2 *
3 * This file is part of OnionCat.
4 *
5 * OnionCat 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, version 3 of the License.
8 *
9 * OnionCat is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with OnionCat. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 /*! ocateth.c
19 * Contains Ethernet (for TAP) and ICMPv6 (for NDP) code.
20 *
21 * @author Bernhard Fischer <rahra _at_ cypherpunk at>
22 * @version 2008/10/10
23 */
24
25
26 #include "ocat.h"
27
28
29 static MACTable_t mac_tbl_[MAX_MAC_ENTRY];
30 static int mac_cnt_ = 0;
31 static pthread_mutex_t mac_mutex_ = PTHREAD_MUTEX_INITIALIZER;
32
33
34 /*! Pseudo header for IPv6 checksum calculation.
35 * RFC2460 8.1, (RFC1885 2.3) RFC2463, RFC1071. */
36 /* RFC2461, rfc2462, RFC2464 ipv6 ethernet enc.
37 * RFC2373 is obsoleted by RFC3513 addressing ipv6
38 * RFC2461 is obsoleted by RFC4861
39 * RFC4862 IPv6 Stateless Address Autoconfiguration
40 * RFC4443 ICMP6 (updates 2780, obsoletes 2463) (20101230)
41 */
42
43 /* IPv6 Ethernet Multicast: (MAC) 33:33:xx:xx:xx:xx, xx -> 4 lowest order bytes of IPv6 destination
44 * Solicited-Node address: (IPv6) FF02:0:0:0:0:1:ffxx:xxxx, -> xx -> 3 lowest order bytes of IPv6 destination (RFC4291)
45 * IPv4 Ethernet Multicast: 01:00:5e:0xx:xx:xx, */
46
47
print_mac_tbl(FILE * f)48 void print_mac_tbl(FILE *f)
49 {
50 int i;
51 char buf[INET6_ADDRSTRLEN];
52
53 //fprintf(f, " # age MAC C address\n");
54 pthread_mutex_lock(&mac_mutex_);
55
56 for (i = 0; i < mac_cnt_; i++)
57 {
58 fprintf(f, "%3d %3d %s ", i, (int) (time(NULL) - mac_tbl_[i].age), ether_ntoa_r((struct ether_addr*) mac_tbl_[i].hwaddr, buf));
59 fprintf(f, "%s ", mac_tbl_[i].family == AF_INET6 ? "IN6" : "IN ");
60 inet_ntop(mac_tbl_[i].family, &mac_tbl_[i].in6addr, buf, INET6_ADDRSTRLEN);
61 fprintf(f, "%s\n", buf);
62 }
63
64 pthread_mutex_unlock(&mac_mutex_);
65 }
66
67
68 /*! Scan MAC table for outages (age > MAX_MAC_AGE) and remove entries.
69 */
mac_cleanup(void)70 void mac_cleanup(void)
71 {
72 int i;
73 #ifdef DEBUG
74 char hw[20];
75 #endif
76
77 pthread_mutex_lock(&mac_mutex_);
78
79 for (i = 0; i < mac_cnt_; i++)
80 if (mac_tbl_[i].age + MAX_MAC_AGE < time(NULL))
81 {
82 log_debug("mac table entry %d (%s) timed out", i, ether_ntoa_r((struct ether_addr*) mac_tbl_[i].hwaddr, hw));
83 memmove(&mac_tbl_[i], &mac_tbl_[i + 1], sizeof(MACTable_t) * (MAX_MAC_ENTRY - i));
84 mac_cnt_--;
85 i--;
86 }
87
88 pthread_mutex_unlock(&mac_mutex_);
89 }
90
91
92 /*! Lookup an entry in the MAC-table by IP, update age.
93 * If hwaddr != NULL and MAC eq 00:00:00:00:00:00 then copy MAC entry
94 * from MAC table to hwaddr, otherwise copy hwaddr to MAC table.
95 * @return -1 if no entry available, otherwise index of entry in table starting with 0.
96 */
mac_set(const struct in6_addr * in6,uint8_t * hwaddr)97 int mac_set(const struct in6_addr *in6, uint8_t *hwaddr)
98 {
99 int i;
100
101 pthread_mutex_lock(&mac_mutex_);
102
103 for (i = mac_cnt_ - 1; i >= 0; i--)
104 if (IN6_ARE_ADDR_EQUAL(in6, &mac_tbl_[i].in6addr))
105 {
106 if (hwaddr)
107 {
108 if (!hwaddr[0] && !hwaddr[1] && !hwaddr[2] && !hwaddr[3] && !hwaddr[4] && !hwaddr[5])
109 memcpy(hwaddr, &mac_tbl_[i].hwaddr, ETHER_ADDR_LEN);
110 else
111 memcpy(&mac_tbl_[i].hwaddr, hwaddr, ETHER_ADDR_LEN);
112 }
113 mac_tbl_[i].age = time(NULL);
114 break;
115 }
116
117 pthread_mutex_unlock(&mac_mutex_);
118
119 return i;
120 }
121
122
123 /*! Wrapper function for mac_set() (see above) to keep valid pointer alignment. */
mac_set_s(struct in6_addr in6,uint8_t * hwaddr)124 int mac_set_s(struct in6_addr in6, uint8_t *hwaddr)
125 {
126 return mac_set(&in6, hwaddr);
127 }
128
129
130 /*! Add MAC/IPv6-pair to MAC table.
131 * @param hwaddr MAC address.
132 * @param in6 IPv6 address.
133 * @return Index of entry (starting with 0) or -1 if MAC table is full (MAX_MAC_ENTRY)
134 */
mac_add_entry(const uint8_t * hwaddr,struct in6_addr in6)135 int mac_add_entry(const uint8_t *hwaddr, struct in6_addr in6)
136 {
137 int e = -1;
138
139 pthread_mutex_lock(&mac_mutex_);
140
141 if (mac_cnt_ < MAX_MAC_ENTRY)
142 {
143 log_debug("adding entry to MAC table %d", mac_cnt_);
144 memcpy(&mac_tbl_[mac_cnt_].hwaddr, hwaddr, ETHER_ADDR_LEN);
145 IN6_ADDR_COPY(&mac_tbl_[mac_cnt_].in6addr, &in6);
146 mac_tbl_[mac_cnt_].age = time(NULL);
147 mac_tbl_[mac_cnt_].family = AF_INET6;
148 e = mac_cnt_++;
149 }
150
151 pthread_mutex_unlock(&mac_mutex_);
152
153 return e;
154 }
155
156
157 /*! Lookup entry by MAC address in MAC-table. It returns the first
158 * occurence and updates the age.
159 * @param hwaddr MAC address to search for.
160 * @param in6 If not NULL, this buffer is filled with the IPv6 address.
161 * @return Index of entry or -1 if no entry exists.
162 */
mac_get_ip(const uint8_t * hwaddr,struct in6_addr * in6)163 int mac_get_ip(const uint8_t *hwaddr, struct in6_addr *in6)
164 {
165 int i;
166
167 pthread_mutex_lock(&mac_mutex_);
168
169 for (i = mac_cnt_ - 1; i >= 0; i--)
170 if (!memcmp(hwaddr, &mac_tbl_[i].hwaddr, ETHER_ADDR_LEN))
171 {
172 if (in6)
173 memcpy(in6, &mac_tbl_[i].in6addr, sizeof(struct in6_addr));
174 mac_tbl_[i].age = time(NULL);
175 break;
176 }
177
178 pthread_mutex_unlock(&mac_mutex_);
179
180 return i;
181 }
182
183
184 /*! Calculate 16 bit one's complement checksum (RFC1071) suitable for ICMPv6.
185 * @param buf Pointer to buffer.
186 * @param len Number of bytes in buffer.
187 * @return Checksum of buffer.
188 */
checksum(const uint16_t * buf,int len)189 uint16_t checksum(const uint16_t *buf, int len)
190 {
191 uint32_t sum = 0;
192
193 // sum up all 16 bit words
194 // (Note that it's endiness independent)
195 for (; len > 1 ; len -= 2, buf++)
196 sum += *buf;
197
198 // add last byte if buffer has odd length
199 if (len)
200 sum += *((uint8_t*) buf);
201
202 // add carries
203 while (sum >> 16)
204 sum = (sum & 0xffff) + (sum >> 16);
205
206 // return complement
207 return ~sum;
208 }
209
210
211 /*! Free checksum buffer.
212 */
free_ckbuf(uint16_t * buf)213 void free_ckbuf(uint16_t *buf)
214 {
215 free(buf);
216 }
217
218
219 /*! Malloc and fill buffer suitable for ICMPv6 checksum calculation.
220 */
malloc_ckbuf(struct in6_addr src,struct in6_addr dst,uint16_t plen,uint8_t proto,const void * payload)221 uint16_t *malloc_ckbuf(struct in6_addr src, struct in6_addr dst, uint16_t plen, uint8_t proto, const void *payload)
222 {
223 struct ip6_psh *psh;
224 uint16_t *psh_u16;
225
226 if (!(psh_u16 = calloc(1, sizeof(struct ip6_psh) + plen)))
227 {
228 log_msg(LOG_EMERG, "error creating checksum buffer: %s", strerror(errno));
229 //return NULL;
230 exit(1);
231 }
232
233 psh = (struct ip6_psh*) psh_u16;
234 psh->src = src;
235 psh->dst = dst;
236 psh->len = htons(plen);
237 psh->nxt = proto;
238 memcpy(psh + 1, payload, plen);
239
240 return psh_u16;
241 }
242
243
244 /*! Send NDP solicitation for dst to appropriate IPv6 multicast address.
245 * @param src Source address.
246 * @param dst Solicited target address.
247 * @return Returns always 0.
248 */
ndp_solicit(const struct in6_addr * src,const struct in6_addr * dst)249 int ndp_solicit(const struct in6_addr *src, const struct in6_addr *dst)
250 {
251 char buf[sizeof(ndp6_t) + sizeof(struct nd_opt_hdr) + 4 + ETHER_ADDR_LEN];
252 ndp6_t *ndp6 = (ndp6_t*) (buf + 4);
253 struct nd_opt_hdr *ohd = (struct nd_opt_hdr*) (ndp6 + 1);
254 uint16_t *ckb;
255 struct in6_addr mcastd = {{{0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0xff, 0, 0, 0}}};
256
257 // clear buffer and setup ipv6 multicast destination
258 memset(buf, 0, sizeof(buf));
259 memcpy(((char*) &mcastd) + 13, ((char*) dst) + 13, 3);
260
261 // tunnel header
262 set_tunheader(buf, htonl(CNF(fhd_key[IPV6_KEY])));
263
264 // ethernet header
265 ndp6->eth.ether_dst[0] = 0x33;
266 ndp6->eth.ether_dst[1] = 0x33;
267 memcpy(&ndp6->eth.ether_dst[2], ((char*) &mcastd) + 12, 4);
268 memcpy(ndp6->eth.ether_src, CNF(ocat_hwaddr), ETHER_ADDR_LEN);
269 ndp6->eth.ether_type = htons(ETHERTYPE_IPV6);
270
271 // ipv6 header
272 ndp6->ip6.ip6_vfc = 0x60;
273 ndp6->ip6.ip6_plen = htons(sizeof(struct nd_neighbor_advert) + sizeof(struct nd_opt_hdr) + ETHER_ADDR_LEN);
274 ndp6->ip6.ip6_nxt = IPPROTO_ICMPV6;
275 ndp6->ip6.ip6_hlim = 255;
276 memcpy(&ndp6->ip6.ip6_src, src, sizeof(struct in6_addr));
277 memcpy(&ndp6->ip6.ip6_dst, &mcastd, sizeof(struct in6_addr));
278
279 // icmpv6 header (partially)
280 ndp6->icmp6.icmp6_type = ND_NEIGHBOR_SOLICIT;
281
282 // ndp solicit header
283 memcpy(&ndp6->ndp_sol.nd_ns_target, dst, sizeof(struct in6_addr));
284
285 // icmpv6 ndp option
286 ohd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
287 ohd->nd_opt_len = 1;
288 memcpy(ohd + 1, ndp6->eth.ether_src, ETHER_ADDR_LEN);
289
290 // calculate checksum
291 ckb = malloc_ckbuf(ndp6->ip6.ip6_src, ndp6->ip6.ip6_dst, ntohs(ndp6->ip6.ip6_plen), IPPROTO_ICMPV6, &ndp6->icmp6);
292 ndp6->icmp6.icmp6_cksum = checksum(ckb, ntohs(ndp6->ip6.ip6_plen) + sizeof(struct ip6_psh));
293 free_ckbuf(ckb);
294
295 #ifdef __CYGWIN__
296 log_debug("writing %d bytes ndp solicitation to TAP driver", sizeof(buf) - 4);
297 // FIXME: there's no error checking
298 win_write_tun(buf + 4, sizeof(buf) - 4);
299 #else
300 log_debug("writing %d bytes ndp solicitation to tunfd %d", sizeof(buf), CNF(tunfd[1]));
301 if (write(CNF(tunfd[1]), buf, sizeof(buf)) < sizeof(buf))
302 log_msg(LOG_ERR, "short write to tun fd %d", CNF(tunfd[1]));
303 #endif
304
305 return 0;
306 }
307
308
309 /*! Wrapper function for macro IN6_IS_ADDR_MULTICAST to keep valid pointer alignment. */
IN6_IS_ADDR_MULTICAST_S(struct in6_addr a)310 static int IN6_IS_ADDR_MULTICAST_S(struct in6_addr a)
311 {
312 return IN6_IS_ADDR_MULTICAST(&a);
313 }
314
315
316 /*! Wrapper function for macro IN6_IS_ADDR_MC_LINKLOCAL to keep valid pointer alignment. */
IN6_IS_ADDR_MC_LINKLOCAL_S(struct in6_addr a)317 static int IN6_IS_ADDR_MC_LINKLOCAL_S(struct in6_addr a)
318 {
319 return IN6_IS_ADDR_MC_LINKLOCAL(&a);
320 }
321
322
323 /*! Wrapper function for macro IN6_IS_ADDR_UNSPECIFIED_S to keep valid pointer alignment. */
IN6_IS_ADDR_UNSPECIFIED_S(struct in6_addr a)324 static int IN6_IS_ADDR_UNSPECIFIED_S(struct in6_addr a)
325 {
326 return IN6_IS_ADDR_UNSPECIFIED(&a);
327 }
328
329
330 /*! Check neighbor solicitation and generate advertisement.
331 * @param buf pointer to frame buffer.
332 * @param rlen buffer length, must be at least sizeof(ICMPv6 header) + 4.
333 * @return 0 if everything gone write, -1 on failure.
334 */
ndp_soladv(char * buf,int rlen)335 int ndp_soladv(char *buf, int rlen)
336 {
337 ndp6_t *ndp6 = (ndp6_t*) (buf + 4);
338 struct nd_opt_hdr *ohd = (struct nd_opt_hdr*) (ndp6 + 1);
339 uint16_t *ckb, cksum;
340 #ifdef DEBUG
341 char hw[20];
342 #endif
343
344 if (ndp6->eth.ether_dst[0] & 1)
345 {
346 // check for right multicast destination on ethernet
347 if (ndp6->eth.ether_dst[2] != 0xff)
348 {
349 log_debug("ethernet multicast destination %s cannot be solicited node address", ether_ntoa_r((struct ether_addr*) ndp6->eth.ether_dst, hw));
350 return -1;
351 }
352
353 // check for right multicast destination in IPv6
354 if (!IN6_IS_ADDR_MULTICAST_S(ndp6->ip6.ip6_dst) || !IN6_IS_ADDR_MC_LINKLOCAL_S(ndp6->ip6.ip6_dst))
355 {
356 log_debug("IPv6 multicast destination not solicited node address");
357 return -1;
358 }
359 }
360
361 ckb = malloc_ckbuf(ndp6->ip6.ip6_src, ndp6->ip6.ip6_dst, ntohs(ndp6->ip6.ip6_plen), IPPROTO_ICMPV6, &ndp6->icmp6);
362 cksum = checksum(ckb, ntohs(ndp6->ip6.ip6_plen) + sizeof(struct ip6_psh));
363 free_ckbuf(ckb);
364
365 if (cksum)
366 {
367 log_msg(LOG_ERR, "icmpv6 checksum wrong");
368 return -1;
369 }
370
371 // check for duplicate address detection
372 if (IN6_IS_ADDR_UNSPECIFIED_S(ndp6->ip6.ip6_src))
373 {
374 log_debug("duplicate address detection in progress");
375 //FIXME: we should check something more here. See RFC2462
376 return -1;
377 }
378
379 struct in6_addr _nst;
380 IN6_ADDR_COPY(&_nst, &ndp6->ndp_sol.nd_ns_target);
381 if (!has_tor_prefix(&_nst))
382 //if (!IN6_HAS_TOR_PREFIX(&ndp6->ndp_sol.nd_ns_target))
383 {
384 log_debug("solicit target is not TOR IPv6");
385 return -1;
386 }
387
388 log_debug("generating response");
389 // add source MAC to table
390 if (mac_set_s(ndp6->ip6.ip6_src, ndp6->eth.ether_src) == -1)
391 if (mac_add_entry(ndp6->eth.ether_src, ndp6->ip6.ip6_src) == -1)
392 {
393 log_msg(LOG_ERR, "MAC table full");
394 return -1;
395 }
396
397 // set MAC addresses for response
398 memcpy(ndp6->eth.ether_dst, ndp6->eth.ether_src, ETHER_ADDR_LEN);
399 memcpy(ndp6->eth.ether_src, CNF(ocat_hwaddr), ETHER_ADDR_LEN);
400
401 // init ip6 header
402 memcpy(&ndp6->ip6.ip6_dst, &ndp6->ip6.ip6_src, sizeof(struct in6_addr));
403 memcpy(&ndp6->ip6.ip6_src, &ndp6->ndp_sol.nd_ns_target, sizeof(struct in6_addr));
404
405 // init nda icmp6 header
406 ndp6->ndp_adv.nd_na_hdr.icmp6_type = ND_NEIGHBOR_ADVERT;
407 ndp6->ndp_adv.nd_na_hdr.icmp6_code = 0;
408 ndp6->ndp_adv.nd_na_hdr.icmp6_cksum = 0;
409 ndp6->ndp_adv.nd_na_flags_reserved = ND_NA_FLAG_SOLICITED;
410
411 //FIXME: setting target option does not check total frame length!
412 ohd->nd_opt_type = ND_OPT_TARGET_LINKADDR;
413 memcpy(ohd + 1, CNF(ocat_hwaddr), ETHER_ADDR_LEN);
414
415 ckb = malloc_ckbuf(ndp6->ip6.ip6_src, ndp6->ip6.ip6_dst, ntohs(ndp6->ip6.ip6_plen), IPPROTO_ICMPV6, &ndp6->icmp6);
416 ndp6->ndp_adv.nd_na_hdr.icmp6_cksum = checksum(ckb, ntohs(ndp6->ip6.ip6_plen) + sizeof(struct ip6_psh));
417 free_ckbuf(ckb);
418
419 #ifdef __CYGWIN__
420 log_debug("writing %d bytes to TAP driver", rlen);
421 // FIXME: there's no error checking
422 win_write_tun(buf + 4, rlen - 4);
423 #else
424 log_debug("writing %d bytes to tunfd %d", rlen, CNF(tunfd[1]));
425 if (write(CNF(tunfd[1]), buf, rlen) < rlen)
426 log_msg(LOG_ERR, "short write");
427 #endif
428
429 return 0;
430 }
431
432
433 /*! Extract source ipv6 and MAC address and add/update MAC table.
434 * FIXME: there should be some additional checks!
435 */
ndp_recadv(char * buf,int len)436 int ndp_recadv(char *buf, int len)
437 {
438 ndp6_t *ndp6 = (ndp6_t*) (buf + 4);
439
440 // add source MAC to table
441 if (mac_set_s(ndp6->ip6.ip6_src, ndp6->eth.ether_src) == -1)
442 if (mac_add_entry(ndp6->eth.ether_src, ndp6->ip6.ip6_src) == -1)
443 {
444 log_msg(LOG_ERR, "MAC table full");
445 return -1;
446 }
447 return 0;
448 }
449
450
eth_ndp(char * buf,int len,int ndp_type)451 int eth_ndp(char *buf, int len, int ndp_type)
452 {
453 switch (ndp_type)
454 {
455 case ND_NEIGHBOR_SOLICIT:
456 log_debug("ND_NEIGHBOR_SOLICIT received");
457 (void) ndp_soladv(buf, len);
458 return 0;
459
460 case ND_NEIGHBOR_ADVERT:
461 log_debug("ND_NEIGHBOR_ADVERT received");
462 (void) ndp_recadv(buf, len);
463 return 0;
464 }
465 return -1;
466 }
467
468
469 /*! Check if destination MAC is designated for OnionCat and
470 * L4-Protocol is ICMPv6.
471 * @return 0 if packet does not match criteria, -1 else.
472 */
eth_check(char * buf,int len)473 int eth_check(char *buf, int len)
474 {
475 ndp6_t *ndp6= (ndp6_t*) (buf + 4);
476
477 // check minimum frame length
478 if (len < sizeof(struct ether_header) + 4)
479 {
480 log_msg(LOG_ERR, "frame too short, len = %d < 4 + %d", len, sizeof(struct ether_header));
481 return E_ETH_TRUNC;
482 }
483
484 // check ethernet destination
485 if ((ndp6->eth.ether_dst[0] != 0x33) && (ndp6->eth.ether_dst[1] != 0x33) && memcmp(ndp6->eth.ether_dst, CNF(ocat_hwaddr), ETHER_ADDR_LEN))
486 {
487 log_debug("unknown destination MAC");
488 return E_ETH_ILLDEST;
489 }
490
491 // check L3 protocol
492 if (ndp6->eth.ether_type != htons(ETHERTYPE_IPV6))
493 {
494 log_msg(LOG_ERR, "L3 protocol not implemented 0x%04x", ntohs(ndp6->eth.ether_type));
495 return E_ETH_ILLPROTO;
496 }
497
498 // check for ndp
499 if ((len >= sizeof(ndp6_t) + 4) && (ndp6->ip6.ip6_nxt == IPPROTO_ICMPV6))
500 {
501 log_debug("ICMPv6 frame intercepted, icmp6_type = %d", ndp6->icmp6.icmp6_type);
502 if (eth_ndp(buf, len, ndp6->icmp6.icmp6_type) != -1)
503 return E_ETH_INTERCEPT;
504 }
505
506 // else forward as usual
507 return 0;
508 }
509
510
511 #ifndef HAVE_ETHER_NTOA
512
513 #define ETHER_ADDR_BUF_SIZE 18
514 static char ether_addr_buf_[ETHER_ADDR_BUF_SIZE];
515
ether_ntoa(const struct ether_addr * addr)516 char *ether_ntoa(const struct ether_addr *addr)
517 {
518 snprintf(ether_addr_buf_, ETHER_ADDR_BUF_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
519 addr->ether_addr_octet[0], addr->ether_addr_octet[1], addr->ether_addr_octet[2],
520 addr->ether_addr_octet[3], addr->ether_addr_octet[4], addr->ether_addr_octet[5]);
521 return ether_addr_buf_;
522 }
523
524 #endif
525
526
527 #ifndef HAVE_ETHER_NTOA_R
528
529 static pthread_mutex_t ether_ntoa_mutex_ = PTHREAD_MUTEX_INITIALIZER;
530
ether_ntoa_r(const struct ether_addr * addr,char * buf)531 char *ether_ntoa_r(const struct ether_addr *addr, char *buf)
532 {
533 if (!buf)
534 return NULL;
535
536 pthread_mutex_lock(ðer_ntoa_mutex_);
537 strlcpy(buf, ether_ntoa((struct ether_addr*) addr), 18);
538 pthread_mutex_unlock(ðer_ntoa_mutex_);
539 return buf;
540 }
541
542 #endif
543
544