xref: /openbsd-src/usr.sbin/tcpdump/print-wg.c (revision 549eab54c481a9723ec27ef854ab4aaff2e31879)
1 /*	$OpenBSD: print-wg.c,v 1.7 2021/09/16 12:35:20 visa 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	1
29 #define RESPONSE	2
30 #define COOKIE		3
31 #define DATA		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
wg_match(const u_char * bp,u_int length)64 wg_match(const u_char *bp, u_int length)
65 {
66 	uint32_t type;
67 
68 	if (length < sizeof(type))
69 		return 0;
70 
71 	if (snapend - bp < sizeof(type)) {
72                 /*
73 		 * we don't have enough bytes to tell if it is wg,
74                  * so don't claim it, and don't claim it's truncated
75                  * wireguard either.
76 		 */
77 		return (0);
78 	}
79 
80 	type = EXTRACT_LE_32BITS(bp);
81 
82 	if (type == INITIATION && length == sizeof(struct wg_initiation))
83 		return INITIATION;
84 	if (type == RESPONSE && length == sizeof(struct wg_response))
85 		return RESPONSE;
86 	if (type == COOKIE && length == sizeof(struct wg_cookie))
87 		return COOKIE;
88 	if (type == DATA && length >= sizeof(struct wg_data))
89 		return DATA;
90 	return 0;
91 }
92 
93 /*
94  * Print WireGuard packet
95  */
96 void
wg_print(const u_char * bp,u_int length)97 wg_print(const u_char *bp, u_int length)
98 {
99 	uint32_t		 type;
100 	uint64_t		 datalength;
101 	struct wg_initiation	*initiation = (void *)bp;
102 	struct wg_response	*response = (void *)bp;
103 	struct wg_cookie	*cookie = (void *)bp;
104 	struct wg_data		*data = (void *)bp;
105 	u_int			 caplen;
106 
107 	caplen = snapend - bp;
108 	if (caplen < sizeof(type))
109 		goto trunc;
110 
111 	if ((type = wg_match(bp, length)) == 0) {
112 		/* doesn't match */
113 		printf("[wg] unknown");
114 		return;
115 	}
116 
117 	switch (type) {
118 	case INITIATION:
119 		printf("[wg] initiation ");
120 		if (caplen < offsetof(struct wg_initiation, fill))
121 			goto trunc;
122 		printf("from 0x%08x", letoh32(initiation->sender));
123 		break;
124 	case RESPONSE:
125 		printf("[wg] response ");
126 		if (caplen < offsetof(struct wg_response, fill))
127 			goto trunc;
128 		printf("from 0x%08x to 0x%08x",
129 		    letoh32(response->sender), letoh32(response->receiver));
130 		break;
131 	case COOKIE:
132 		printf("[wg] cookie ");
133 		if (caplen < offsetof(struct wg_cookie, fill))
134 			goto trunc;
135 		printf(" to 0x%08x", letoh32(cookie->receiver));
136 		break;
137 	case DATA:
138 		datalength = length - sizeof(struct wg_data);
139 		if (datalength != 0)
140 			printf("[wg] data length %llu ", datalength);
141 		else
142 			printf("[wg] keepalive ");
143 		if (caplen < offsetof(struct wg_data, mac))
144 			goto trunc;
145 		/* data->nonce may be unaligned. */
146 		printf("to 0x%08x nonce %llu",
147 		    letoh32(data->receiver), EXTRACT_LE_64BITS(&data->nonce));
148 		break;
149 	}
150 	return;
151 
152 trunc:
153 	printf("[|wg]");
154 }
155