xref: /openbsd-src/usr.sbin/tcpdump/print-wg.c (revision c020cf82e0cc147236f01a8dca7052034cf9d30d)
1 /*	$OpenBSD: print-wg.c,v 1.4 2020/06/21 07:14:17 tb Exp $ */
2 
3 /*
4  * Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
5  * Copyright (C) 2019-2020 Matt Dunwoodie <ncon@noconroy.net>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/types.h>
21 
22 #include <stdio.h>
23 #include <stddef.h>
24 
25 #include "interface.h"
26 #include "extract.h"
27 
28 #define INITIATION	htole32(1)
29 #define RESPONSE	htole32(2)
30 #define COOKIE		htole32(3)
31 #define DATA		htole32(4)
32 
33 struct wg_initiation {
34 	uint32_t	type;
35 	uint32_t	sender;
36 	uint8_t		fill[140]; /* Includes ephemeral + MAC */
37 };
38 
39 struct wg_response {
40 	uint32_t	type;
41 	uint32_t	sender;
42 	uint32_t	receiver;
43 	uint8_t		fill[80]; /* Includes ephemeral + MAC */
44 };
45 
46 struct wg_cookie {
47 	uint32_t	type;
48 	uint32_t	receiver;
49 	uint8_t		fill[56]; /* Includes nonce + encrypted cookie */
50 };
51 
52 struct wg_data {
53 	uint32_t	type;
54 	uint32_t	receiver;
55 	uint64_t	nonce;
56 	/* uint8_t	data[variable]; - Variable length data */
57 	uint8_t		mac[16];
58 };
59 
60 /*
61  * Check if packet is a WireGuard packet, as WireGuard may run on any port.
62  */
63 uint32_t
64 wg_match(const u_char *bp, u_int length)
65 {
66 	u_int caplen;
67 	uint32_t type;
68 
69 	if (length < sizeof(type))
70 		return 0;
71 
72 	if (snapend - bp < sizeof(type)) {
73                 /*
74 		 * we don't have enough bytes to tell if it is wg,
75                  * so don't claim it, and don't claim it's truncated
76                  * wireguard either.
77 		 */
78 		return (0);
79 	}
80 
81 	type = EXTRACT_LE_32BITS(bp);
82 
83 	if (type == INITIATION && length == sizeof(struct wg_initiation))
84 		return INITIATION;
85 	if (type == RESPONSE && length == sizeof(struct wg_response))
86 		return RESPONSE;
87 	if (type == COOKIE && length == sizeof(struct wg_cookie))
88 		return COOKIE;
89 	if (type == DATA && length >= sizeof(struct wg_data))
90 		return DATA;
91 	return 0;
92 }
93 
94 /*
95  * Print WireGuard packet
96  */
97 void
98 wg_print(const u_char *bp, u_int length)
99 {
100 	uint32_t		 type;
101 	uint64_t		 datalength;
102 	struct wg_initiation	*initiation = (void *)bp;
103 	struct wg_response	*response = (void *)bp;
104 	struct wg_cookie	*cookie = (void *)bp;
105 	struct wg_data		*data = (void *)bp;
106 	u_int			 caplen;
107 
108 	caplen = snapend - bp;
109 	if (caplen < sizeof(type))
110 		goto trunc;
111 
112 	if ((type = wg_match(bp, length)) == 0) {
113 		/* doesn't match */
114 		printf("[wg] unknown");
115 		return;
116 	}
117 
118 	switch (type) {
119 	case INITIATION:
120 		printf("[wg] initiation ");
121 		if (caplen < offsetof(struct wg_initiation, fill))
122 			goto trunc;
123 		printf("from 0x%08x", letoh32(initiation->sender));
124 		break;
125 	case RESPONSE:
126 		printf("[wg] response ");
127 		if (caplen < offsetof(struct wg_response, fill))
128 			goto trunc;
129 		printf("from 0x%08x to 0x%08x",
130 		    letoh32(response->sender), letoh32(response->receiver));
131 		break;
132 	case COOKIE:
133 		printf("[wg] cookie ");
134 		if (caplen < offsetof(struct wg_cookie, fill))
135 			goto trunc;
136 		printf(" to 0x%08x", letoh32(cookie->receiver));
137 		break;
138 	case DATA:
139 		datalength = length - sizeof(struct wg_data);
140 		if (datalength != 0)
141 			printf("[wg] data length %llu ", datalength);
142 		else
143 			printf("[wg] keepalive ");
144 		if (caplen < offsetof(struct wg_data, mac))
145 			goto trunc;
146 		printf("to 0x%08x nonce %llu",
147 		    letoh32(data->receiver), letoh64(data->nonce));
148 		break;
149 	}
150 	return;
151 
152 trunc:
153 	printf("[|wg]");
154 }
155