summaryrefslogtreecommitdiff
path: root/usr.sbin/tcpdump/print-wg.c
blob: b10bfd9389590a1515f67575529fe7a52606dafd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*	$OpenBSD: print-wg.c,v 1.7 2021/09/16 12:35:20 visa Exp $ */

/*
 * Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
 * Copyright (C) 2019-2020 Matt Dunwoodie <ncon@noconroy.net>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/types.h>

#include <stdio.h>
#include <stddef.h>

#include "interface.h"
#include "extract.h"

#define INITIATION	1
#define RESPONSE	2
#define COOKIE		3
#define DATA		4

struct wg_initiation {
	uint32_t	type;
	uint32_t	sender;
	uint8_t		fill[140]; /* Includes ephemeral + MAC */
};

struct wg_response {
	uint32_t	type;
	uint32_t	sender;
	uint32_t	receiver;
	uint8_t		fill[80]; /* Includes ephemeral + MAC */
};

struct wg_cookie {
	uint32_t	type;
	uint32_t	receiver;
	uint8_t		fill[56]; /* Includes nonce + encrypted cookie */
};

struct wg_data {
	uint32_t	type;
	uint32_t	receiver;
	uint64_t	nonce;
	/* uint8_t	data[variable]; - Variable length data */
	uint8_t		mac[16];
};

/*
 * Check if packet is a WireGuard packet, as WireGuard may run on any port.
 */
uint32_t
wg_match(const u_char *bp, u_int length)
{
	uint32_t type;

	if (length < sizeof(type))
		return 0;

	if (snapend - bp < sizeof(type)) {
                /*
		 * we don't have enough bytes to tell if it is wg,
                 * so don't claim it, and don't claim it's truncated
                 * wireguard either.
		 */
		return (0);
	}

	type = EXTRACT_LE_32BITS(bp);

	if (type == INITIATION && length == sizeof(struct wg_initiation))
		return INITIATION;
	if (type == RESPONSE && length == sizeof(struct wg_response))
		return RESPONSE;
	if (type == COOKIE && length == sizeof(struct wg_cookie))
		return COOKIE;
	if (type == DATA && length >= sizeof(struct wg_data))
		return DATA;
	return 0;
}

/*
 * Print WireGuard packet
 */
void
wg_print(const u_char *bp, u_int length)
{
	uint32_t		 type;
	uint64_t		 datalength;
	struct wg_initiation	*initiation = (void *)bp;
	struct wg_response	*response = (void *)bp;
	struct wg_cookie	*cookie = (void *)bp;
	struct wg_data		*data = (void *)bp;
	u_int			 caplen;

	caplen = snapend - bp;
	if (caplen < sizeof(type))
		goto trunc;

	if ((type = wg_match(bp, length)) == 0) {
		/* doesn't match */
		printf("[wg] unknown");
		return;
	}

	switch (type) {
	case INITIATION:
		printf("[wg] initiation ");
		if (caplen < offsetof(struct wg_initiation, fill))
			goto trunc;
		printf("from 0x%08x", letoh32(initiation->sender));
		break;
	case RESPONSE:
		printf("[wg] response ");
		if (caplen < offsetof(struct wg_response, fill))
			goto trunc;
		printf("from 0x%08x to 0x%08x",
		    letoh32(response->sender), letoh32(response->receiver));
		break;
	case COOKIE:
		printf("[wg] cookie ");
		if (caplen < offsetof(struct wg_cookie, fill))
			goto trunc;
		printf(" to 0x%08x", letoh32(cookie->receiver));
		break;
	case DATA:
		datalength = length - sizeof(struct wg_data);
		if (datalength != 0)
			printf("[wg] data length %llu ", datalength);
		else
			printf("[wg] keepalive ");
		if (caplen < offsetof(struct wg_data, mac))
			goto trunc;
		/* data->nonce may be unaligned. */
		printf("to 0x%08x nonce %llu",
		    letoh32(data->receiver), EXTRACT_LE_64BITS(&data->nonce));
		break;
	}
	return;

trunc:
	printf("[|wg]");
}