[BACK]Return to print-wg.c CVS log [TXT][DIR] Up to [local] / src / usr.sbin / tcpdump

File: [local] / src / usr.sbin / tcpdump / print-wg.c (download)

Revision 1.7, Thu Sep 16 12:35:20 2021 UTC (2 years, 8 months ago) by visa
Branch: MAIN
CVS Tags: OPENBSD_7_5_BASE, OPENBSD_7_5, OPENBSD_7_4_BASE, OPENBSD_7_4, OPENBSD_7_3_BASE, OPENBSD_7_3, OPENBSD_7_2_BASE, OPENBSD_7_2, OPENBSD_7_1_BASE, OPENBSD_7_1, OPENBSD_7_0_BASE, OPENBSD_7_0, HEAD
Changes since 1.6: +3 -2 lines

tcpdump: Fix data alignment issue in WireGuard printer

Access 8-byte nonce as unaligned data to avoid a crash on strict
alignment architectures. With IP and UDP, payload alignment is
guaranteed to 4-byte boundary only.

Reported and tested by Peter J. Philipp

OK deraadt@

/*	$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]");
}