1 /* 2 * Copyright (c) 2012 Gleb Smirnoff <glebius@FreeBSD.org> 3 * Copyright (c) 2002 Michael Shalayeff 4 * Copyright (c) 2001 Daniel Hartmeier 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 * THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $OpenBSD: print-pfsync.c,v 1.38 2012/09/19 13:50:36 mikeb Exp $ 29 * $OpenBSD: pf_print_state.c,v 1.11 2012/07/08 17:48:37 lteo Exp $ 30 */ 31 32 #ifdef HAVE_CONFIG_H 33 #include "config.h" 34 #endif 35 36 #ifndef HAVE_NET_PFVAR_H 37 #error "No pf headers available" 38 #endif 39 #include <sys/endian.h> 40 #include <net/if.h> 41 #include <net/pfvar.h> 42 #include <net/if_pfsync.h> 43 #define TCPSTATES 44 #include <netinet/tcp_fsm.h> 45 46 #include <netdissect-stdinc.h> 47 #include <string.h> 48 49 #include "netdissect.h" 50 #include "interface.h" 51 #include "addrtoname.h" 52 53 static void pfsync_print(netdissect_options *, struct pfsync_header *, 54 const u_char *, u_int); 55 static void print_src_dst(netdissect_options *, 56 const struct pf_state_peer_export *, 57 const struct pf_state_peer_export *, uint8_t); 58 static void print_state(netdissect_options *, union pfsync_state_union *, int); 59 60 void 61 pfsync_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, 62 register const u_char *p) 63 { 64 u_int caplen = h->caplen; 65 66 ts_print(ndo, &h->ts); 67 68 if (caplen < PFSYNC_HDRLEN) { 69 ND_PRINT("[|pfsync]"); 70 goto out; 71 } 72 73 pfsync_print(ndo, (struct pfsync_header *)p, 74 p + sizeof(struct pfsync_header), 75 caplen - sizeof(struct pfsync_header)); 76 out: 77 if (ndo->ndo_xflag) { 78 hex_print(ndo, "\n\t", p, caplen); 79 } 80 fn_print_char(ndo, '\n'); 81 return; 82 } 83 84 void 85 pfsync_ip_print(netdissect_options *ndo , const u_char *bp, u_int len) 86 { 87 struct pfsync_header *hdr = (struct pfsync_header *)bp; 88 89 if (len < PFSYNC_HDRLEN || !ND_TTEST_LEN(bp, len)) 90 ND_PRINT("[|pfsync]"); 91 else 92 pfsync_print(ndo, hdr, bp + sizeof(struct pfsync_header), 93 len - sizeof(struct pfsync_header)); 94 } 95 96 struct pfsync_actions { 97 const char *name; 98 size_t len; 99 void (*print)(netdissect_options *, const void *); 100 }; 101 102 static void pfsync_print_clr(netdissect_options *, const void *); 103 static void pfsync_print_state_1301(netdissect_options *, const void *); 104 static void pfsync_print_state_1400(netdissect_options *, const void *); 105 static void pfsync_print_state_1500(netdissect_options *, const void *); 106 static void pfsync_print_ins_ack(netdissect_options *, const void *); 107 static void pfsync_print_upd_c(netdissect_options *, const void *); 108 static void pfsync_print_upd_req(netdissect_options *, const void *); 109 static void pfsync_print_del_c(netdissect_options *, const void *); 110 static void pfsync_print_bus(netdissect_options *, const void *); 111 static void pfsync_print_tdb(netdissect_options *, const void *); 112 113 struct pfsync_actions actions[] = { 114 { "clear all", sizeof(struct pfsync_clr), pfsync_print_clr }, 115 { "insert 13.1", sizeof(struct pfsync_state_1301), 116 pfsync_print_state_1301 }, 117 { "insert ack", sizeof(struct pfsync_ins_ack), pfsync_print_ins_ack }, 118 { "update 13.1", sizeof(struct pfsync_state_1301), 119 pfsync_print_state_1301 }, 120 { "update compressed", sizeof(struct pfsync_upd_c), 121 pfsync_print_upd_c }, 122 { "request uncompressed", sizeof(struct pfsync_upd_req), 123 pfsync_print_upd_req }, 124 { "delete", sizeof(struct pfsync_state_1301), pfsync_print_state_1301 }, 125 { "delete compressed", sizeof(struct pfsync_del_c), 126 pfsync_print_del_c }, 127 { "frag insert", 0, NULL }, 128 { "frag delete", 0, NULL }, 129 { "bulk update status", sizeof(struct pfsync_bus), 130 pfsync_print_bus }, 131 { "tdb", 0, pfsync_print_tdb }, 132 { "eof", 0, NULL }, 133 { "insert", sizeof(struct pfsync_state_1400), pfsync_print_state_1400 }, 134 { "update", sizeof(struct pfsync_state_1400), pfsync_print_state_1400 }, 135 { "insert", sizeof(struct pfsync_state_1500), pfsync_print_state_1500 }, 136 { "update", sizeof(struct pfsync_state_1500), pfsync_print_state_1500 }, 137 }; 138 139 static void 140 pfsync_print(netdissect_options *ndo, struct pfsync_header *hdr, 141 const u_char *bp, u_int len) 142 { 143 struct pfsync_subheader *subh; 144 int count, plen, i; 145 u_int alen; 146 147 plen = ntohs(hdr->len); 148 149 ND_PRINT("PFSYNCv%d len %d", hdr->version, plen); 150 151 if (hdr->version != PFSYNC_VERSION) 152 return; 153 154 plen -= sizeof(*hdr); 155 156 while (plen > 0) { 157 if (len < sizeof(*subh)) 158 break; 159 160 subh = (struct pfsync_subheader *)bp; 161 bp += sizeof(*subh); 162 len -= sizeof(*subh); 163 plen -= sizeof(*subh); 164 165 if (subh->action >= PFSYNC_ACT_MAX) { 166 ND_PRINT("\n act UNKNOWN id %d", 167 subh->action); 168 return; 169 } 170 171 count = ntohs(subh->count); 172 ND_PRINT("\n %s count %d", actions[subh->action].name, 173 count); 174 alen = actions[subh->action].len; 175 176 if (subh->action == PFSYNC_ACT_EOF) 177 return; 178 179 if (actions[subh->action].print == NULL) { 180 ND_PRINT("\n unimplemented action %hhu", 181 subh->action); 182 return; 183 } 184 185 for (i = 0; i < count; i++) { 186 if (len < alen) { 187 len = 0; 188 break; 189 } 190 191 if (ndo->ndo_vflag) 192 actions[subh->action].print(ndo, bp); 193 194 bp += alen; 195 len -= alen; 196 plen -= alen; 197 } 198 } 199 200 if (plen > 0) { 201 ND_PRINT("\n ..."); 202 return; 203 } 204 if (plen < 0) { 205 ND_PRINT("\n invalid header length"); 206 return; 207 } 208 if (len > 0) 209 ND_PRINT("\n invalid packet length"); 210 } 211 212 static void 213 pfsync_print_clr(netdissect_options *ndo, const void *bp) 214 { 215 const struct pfsync_clr *clr = bp; 216 217 ND_PRINT("\n\tcreatorid: %08x", htonl(clr->creatorid)); 218 if (clr->ifname[0] != '\0') 219 ND_PRINT(" interface: %s", clr->ifname); 220 } 221 222 static void 223 pfsync_print_state_1301(netdissect_options *ndo, const void *bp) 224 { 225 struct pfsync_state_1301 *st = (struct pfsync_state_1301 *)bp; 226 227 fn_print_char(ndo, '\n'); 228 print_state(ndo, (union pfsync_state_union *)st, PFSYNC_MSG_VERSION_1301); 229 } 230 231 static void 232 pfsync_print_state_1400(netdissect_options *ndo, const void *bp) 233 { 234 struct pfsync_state_1400 *st = (struct pfsync_state_1400 *)bp; 235 236 fn_print_char(ndo, '\n'); 237 print_state(ndo, (union pfsync_state_union *)st, PFSYNC_MSG_VERSION_1400); 238 } 239 240 static void 241 pfsync_print_state_1500(netdissect_options *ndo, const void *bp) 242 { 243 struct pfsync_state_1500 *st = (struct pfsync_state_1500 *)bp; 244 245 fn_print_char(ndo, '\n'); 246 print_state(ndo, (union pfsync_state_union *)st, PFSYNC_MSG_VERSION_1500); 247 } 248 249 static void 250 pfsync_print_ins_ack(netdissect_options *ndo, const void *bp) 251 { 252 const struct pfsync_ins_ack *iack = bp; 253 254 ND_PRINT("\n\tid: %016jx creatorid: %08x", 255 (uintmax_t)be64toh(iack->id), ntohl(iack->creatorid)); 256 } 257 258 static void 259 pfsync_print_upd_c(netdissect_options *ndo, const void *bp) 260 { 261 const struct pfsync_upd_c *u = bp; 262 263 ND_PRINT("\n\tid: %016jx creatorid: %08x", 264 (uintmax_t)be64toh(u->id), ntohl(u->creatorid)); 265 if (ndo->ndo_vflag > 2) { 266 ND_PRINT("\n\tTCP? :"); 267 print_src_dst(ndo, &u->src, &u->dst, IPPROTO_TCP); 268 } 269 } 270 271 static void 272 pfsync_print_upd_req(netdissect_options *ndo, const void *bp) 273 { 274 const struct pfsync_upd_req *ur = bp; 275 276 ND_PRINT("\n\tid: %016jx creatorid: %08x", 277 (uintmax_t)be64toh(ur->id), ntohl(ur->creatorid)); 278 } 279 280 static void 281 pfsync_print_del_c(netdissect_options *ndo, const void *bp) 282 { 283 const struct pfsync_del_c *d = bp; 284 285 ND_PRINT("\n\tid: %016jx creatorid: %08x", 286 (uintmax_t)be64toh(d->id), ntohl(d->creatorid)); 287 } 288 289 static void 290 pfsync_print_bus(netdissect_options *ndo, const void *bp) 291 { 292 const struct pfsync_bus *b = bp; 293 uint32_t endtime; 294 int min, sec; 295 const char *status; 296 297 endtime = ntohl(b->endtime); 298 sec = endtime % 60; 299 endtime /= 60; 300 min = endtime % 60; 301 endtime /= 60; 302 303 switch (b->status) { 304 case PFSYNC_BUS_START: 305 status = "start"; 306 break; 307 case PFSYNC_BUS_END: 308 status = "end"; 309 break; 310 default: 311 status = "UNKNOWN"; 312 break; 313 } 314 315 ND_PRINT("\n\tcreatorid: %08x age: %.2u:%.2u:%.2u status: %s", 316 htonl(b->creatorid), endtime, min, sec, status); 317 } 318 319 static void 320 pfsync_print_tdb(netdissect_options *ndo, const void *bp) 321 { 322 const struct pfsync_tdb *t = bp; 323 324 ND_PRINT("\n\tspi: 0x%08x rpl: %ju cur_bytes: %ju", 325 ntohl(t->spi), (uintmax_t )be64toh(t->rpl), 326 (uintmax_t )be64toh(t->cur_bytes)); 327 } 328 329 static void 330 print_host(netdissect_options *ndo, struct pf_addr *addr, uint16_t port, 331 sa_family_t af, const char *proto) 332 { 333 char buf[48]; 334 335 if (inet_ntop(af, addr, buf, sizeof(buf)) == NULL) 336 ND_PRINT("?"); 337 else 338 ND_PRINT("%s", buf); 339 340 if (port) 341 ND_PRINT(".%hu", ntohs(port)); 342 } 343 344 static void 345 print_seq(netdissect_options *ndo, const struct pf_state_peer_export *p) 346 { 347 if (p->seqdiff) 348 ND_PRINT("[%u + %u](+%u)", ntohl(p->seqlo), 349 ntohl(p->seqhi) - ntohl(p->seqlo), ntohl(p->seqdiff)); 350 else 351 ND_PRINT("[%u + %u]", ntohl(p->seqlo), 352 ntohl(p->seqhi) - ntohl(p->seqlo)); 353 } 354 355 static void 356 print_src_dst(netdissect_options *ndo, const struct pf_state_peer_export *src, 357 const struct pf_state_peer_export *dst, uint8_t proto) 358 { 359 360 if (proto == IPPROTO_TCP) { 361 if (src->state <= TCPS_TIME_WAIT && 362 dst->state <= TCPS_TIME_WAIT) 363 ND_PRINT(" %s:%s", tcpstates[src->state], 364 tcpstates[dst->state]); 365 else if (src->state == PF_TCPS_PROXY_SRC || 366 dst->state == PF_TCPS_PROXY_SRC) 367 ND_PRINT(" PROXY:SRC"); 368 else if (src->state == PF_TCPS_PROXY_DST || 369 dst->state == PF_TCPS_PROXY_DST) 370 ND_PRINT(" PROXY:DST"); 371 else 372 ND_PRINT(" <BAD STATE LEVELS %u:%u>", 373 src->state, dst->state); 374 if (ndo->ndo_vflag > 1) { 375 ND_PRINT("\n\t"); 376 print_seq(ndo, src); 377 if (src->wscale && dst->wscale) 378 ND_PRINT(" wscale %u", 379 src->wscale & PF_WSCALE_MASK); 380 ND_PRINT(" "); 381 print_seq(ndo, dst); 382 if (src->wscale && dst->wscale) 383 ND_PRINT(" wscale %u", 384 dst->wscale & PF_WSCALE_MASK); 385 } 386 } else if (proto == IPPROTO_UDP && src->state < PFUDPS_NSTATES && 387 dst->state < PFUDPS_NSTATES) { 388 const char *states[] = PFUDPS_NAMES; 389 390 ND_PRINT(" %s:%s", states[src->state], states[dst->state]); 391 } else if (proto != IPPROTO_ICMP && src->state < PFOTHERS_NSTATES && 392 dst->state < PFOTHERS_NSTATES) { 393 /* XXX ICMP doesn't really have state levels */ 394 const char *states[] = PFOTHERS_NAMES; 395 396 ND_PRINT(" %s:%s", states[src->state], states[dst->state]); 397 } else { 398 ND_PRINT(" %u:%u", src->state, dst->state); 399 } 400 } 401 402 static void 403 print_state(netdissect_options *ndo, union pfsync_state_union *s, int version) 404 { 405 struct pf_state_peer_export *src, *dst; 406 struct pfsync_state_key *sk, *nk; 407 int min, sec; 408 409 if (s->pfs_1301.direction == PF_OUT) { 410 src = &s->pfs_1301.src; 411 dst = &s->pfs_1301.dst; 412 sk = &s->pfs_1301.key[PF_SK_STACK]; 413 nk = &s->pfs_1301.key[PF_SK_WIRE]; 414 if (s->pfs_1301.proto == IPPROTO_ICMP || s->pfs_1301.proto == IPPROTO_ICMPV6) 415 sk->port[0] = nk->port[0]; 416 } else { 417 src = &s->pfs_1301.dst; 418 dst = &s->pfs_1301.src; 419 sk = &s->pfs_1301.key[PF_SK_WIRE]; 420 nk = &s->pfs_1301.key[PF_SK_STACK]; 421 if (s->pfs_1301.proto == IPPROTO_ICMP || s->pfs_1301.proto == IPPROTO_ICMPV6) 422 sk->port[1] = nk->port[1]; 423 } 424 ND_PRINT("\t%s ", s->pfs_1301.ifname); 425 ND_PRINT("proto %u ", s->pfs_1301.proto); 426 427 print_host(ndo, &nk->addr[1], nk->port[1], s->pfs_1301.af, NULL); 428 if (PF_ANEQ(&nk->addr[1], &sk->addr[1], s->pfs_1301.af) || 429 nk->port[1] != sk->port[1]) { 430 ND_PRINT((" (")); 431 print_host(ndo, &sk->addr[1], sk->port[1], s->pfs_1301.af, NULL); 432 ND_PRINT(")"); 433 } 434 if (s->pfs_1301.direction == PF_OUT) 435 ND_PRINT((" -> ")); 436 else 437 ND_PRINT((" <- ")); 438 print_host(ndo, &nk->addr[0], nk->port[0], s->pfs_1301.af, NULL); 439 if (PF_ANEQ(&nk->addr[0], &sk->addr[0], s->pfs_1301.af) || 440 nk->port[0] != sk->port[0]) { 441 ND_PRINT((" (")); 442 print_host(ndo, &sk->addr[0], sk->port[0], s->pfs_1301.af, NULL); 443 ND_PRINT((")")); 444 } 445 446 print_src_dst(ndo, src, dst, s->pfs_1301.proto); 447 448 if (ndo->ndo_vflag > 1) { 449 uint64_t packets[2]; 450 uint64_t bytes[2]; 451 uint32_t creation = ntohl(s->pfs_1301.creation); 452 uint32_t expire = ntohl(s->pfs_1301.expire); 453 454 sec = creation % 60; 455 creation /= 60; 456 min = creation % 60; 457 creation /= 60; 458 ND_PRINT("\n\tage %.2u:%.2u:%.2u", creation, min, sec); 459 sec = expire % 60; 460 expire /= 60; 461 min = expire % 60; 462 expire /= 60; 463 ND_PRINT(", expires in %.2u:%.2u:%.2u", expire, min, sec); 464 465 bcopy(s->pfs_1301.packets[0], &packets[0], sizeof(uint64_t)); 466 bcopy(s->pfs_1301.packets[1], &packets[1], sizeof(uint64_t)); 467 bcopy(s->pfs_1301.bytes[0], &bytes[0], sizeof(uint64_t)); 468 bcopy(s->pfs_1301.bytes[1], &bytes[1], sizeof(uint64_t)); 469 ND_PRINT(", %ju:%ju pkts, %ju:%ju bytes", 470 be64toh(packets[0]), be64toh(packets[1]), 471 be64toh(bytes[0]), be64toh(bytes[1])); 472 if (s->pfs_1301.anchor != ntohl(-1)) 473 ND_PRINT(", anchor %u", ntohl(s->pfs_1301.anchor)); 474 if (s->pfs_1301.rule != ntohl(-1)) 475 ND_PRINT(", rule %u", ntohl(s->pfs_1301.rule)); 476 } 477 if (ndo->ndo_vflag > 1) { 478 uint64_t id; 479 480 bcopy(&s->pfs_1301.id, &id, sizeof(uint64_t)); 481 ND_PRINT("\n\tid: %016jx creatorid: %08x", 482 (uintmax_t )be64toh(id), ntohl(s->pfs_1301.creatorid)); 483 } 484 } 485