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