static int verifypriority(struct sadb_msg *m) { caddr_t mhp[SADB_EXT_MAX + 1]; struct sadb_x_policy *xpl; /* check pfkey message. */ if (pfkey_align(m, mhp)) { printf("(%s\n", ipsec_strerror()); return 0; } if (pfkey_check(mhp)) { printf("%s\n", ipsec_strerror()); return 0; } xpl = (struct sadb_x_policy *) mhp[SADB_X_EXT_POLICY]; if (xpl == NULL) { printf("no X_POLICY extension.\n"); return 0; } /* now make sure they match */ if (last_priority != xpl->sadb_x_policy_priority) return 0; return 1; }
void pfkey_spdump(struct sadb_msg *m) { char pbuf[NI_MAXSERV]; caddr_t mhp[SADB_EXT_MAX + 1]; struct sadb_address *m_saddr, *m_daddr; struct sadb_x_policy *m_xpl; struct sadb_lifetime *m_lft = NULL; struct sockaddr *sa; u_int16_t port; /* check pfkey message. */ if (pfkey_align(m, mhp)) { printf("%s\n", ipsec_strerror()); return; } if (pfkey_check(mhp)) { printf("%s\n", ipsec_strerror()); return; } m_saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; m_daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; m_xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; m_lft = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; /* source address */ if (m_saddr == NULL) { printf("no ADDRESS_SRC extension.\n"); return; } sa = (struct sockaddr *)(m_saddr + 1); switch (sa->sa_family) { case AF_INET: case AF_INET6: if (getnameinfo(sa, sa->sa_len, NULL, 0, pbuf, sizeof(pbuf), NI_NUMERICSERV) != 0) port = 0; /*XXX*/ else port = atoi(pbuf); printf("%s%s ", str_ipaddr(sa), str_prefport(sa->sa_family, m_saddr->sadb_address_prefixlen, port)); break; default: printf("unknown-af "); break; } /* destination address */ if (m_daddr == NULL) { printf("no ADDRESS_DST extension.\n"); return; } sa = (struct sockaddr *)(m_daddr + 1); switch (sa->sa_family) { case AF_INET: case AF_INET6: if (getnameinfo(sa, sa->sa_len, NULL, 0, pbuf, sizeof(pbuf), NI_NUMERICSERV) != 0) port = 0; /*XXX*/ else port = atoi(pbuf); printf("%s%s ", str_ipaddr(sa), str_prefport(sa->sa_family, m_daddr->sadb_address_prefixlen, port)); break; default: printf("unknown-af "); break; } /* upper layer protocol */ if (m_saddr->sadb_address_proto != m_daddr->sadb_address_proto) { printf("upper layer protocol mismatched.\n"); return; } if (m_saddr->sadb_address_proto == IPSEC_ULPROTO_ANY) printf("any"); else GETMSGSTR(str_upper, m_saddr->sadb_address_proto); /* policy */ { char *d_xpl; if (m_xpl == NULL) { printf("no X_POLICY extension.\n"); return; } d_xpl = ipsec_dump_policy((char *)m_xpl, "\n\t"); /* dump SPD */ printf("\n\t%s\n", d_xpl); free(d_xpl); } /* lifetime */ if (m_lft) { printf("\tlifetime:%lu validtime:%lu\n", (u_long)m_lft->sadb_lifetime_addtime, (u_long)m_lft->sadb_lifetime_usetime); } printf("\tspid=%ld seq=%ld pid=%ld\n", (u_long)m_xpl->sadb_x_policy_id, (u_long)m->sadb_msg_seq, (u_long)m->sadb_msg_pid); /* XXX TEST */ printf("\trefcnt=%u\n", m->sadb_msg_reserved); return; }
/* * dump SADB_MSG formated. For debugging, you should use kdebug_sadb(). */ void pfkey_sadump(struct sadb_msg *m) { caddr_t mhp[SADB_EXT_MAX + 1]; struct sadb_sa *m_sa; struct sadb_x_sa2 *m_sa2; struct sadb_lifetime *m_lftc, *m_lfth, *m_lfts; struct sadb_address *m_saddr, *m_daddr; struct sadb_key *m_auth, *m_enc; /* check pfkey message. */ if (pfkey_align(m, mhp)) { printf("%s\n", ipsec_strerror()); return; } if (pfkey_check(mhp)) { printf("%s\n", ipsec_strerror()); return; } m_sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; m_sa2 = (struct sadb_x_sa2 *)mhp[SADB_X_EXT_SA2]; m_lftc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT]; m_lfth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; m_lfts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT]; m_saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; m_daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; m_auth = (struct sadb_key *)mhp[SADB_EXT_KEY_AUTH]; m_enc = (struct sadb_key *)mhp[SADB_EXT_KEY_ENCRYPT]; /* source address */ if (m_saddr == NULL) { printf("no ADDRESS_SRC extension.\n"); return; } printf("%s ", str_ipaddr((struct sockaddr *)(m_saddr + 1))); /* destination address */ if (m_daddr == NULL) { printf("no ADDRESS_DST extension.\n"); return; } printf("%s ", str_ipaddr((struct sockaddr *)(m_daddr + 1))); /* SA type */ if (m_sa == NULL) { printf("no SA extension.\n"); return; } if (m_sa2 == NULL) { printf("no SA2 extension.\n"); return; } printf("\n\t"); GETMSGSTR(str_satype, m->sadb_msg_satype); printf("mode="); GETMSGSTR(str_mode, m_sa2->sadb_x_sa2_mode); printf("spi=%u(0x%08x) reqid=%u(0x%08x)\n", (u_int32_t)ntohl(m_sa->sadb_sa_spi), (u_int32_t)ntohl(m_sa->sadb_sa_spi), (u_int32_t)m_sa2->sadb_x_sa2_reqid, (u_int32_t)m_sa2->sadb_x_sa2_reqid); /* encryption key */ if (m->sadb_msg_satype == SADB_X_SATYPE_IPCOMP) { printf("\tC: "); GETMSGV2S(str_alg_comp, m_sa->sadb_sa_encrypt); } else if (m->sadb_msg_satype == SADB_SATYPE_ESP) { if (m_enc != NULL) { printf("\tE: "); GETMSGV2S(str_alg_enc, m_sa->sadb_sa_encrypt); ipsec_hexdump((caddr_t)m_enc + sizeof(*m_enc), m_enc->sadb_key_bits / 8); printf("\n"); } } /* authentication key */ if (m_auth != NULL) { printf("\tA: "); GETMSGV2S(str_alg_auth, m_sa->sadb_sa_auth); ipsec_hexdump((caddr_t)m_auth + sizeof(*m_auth), m_auth->sadb_key_bits / 8); printf("\n"); } /* replay windoe size & flags */ printf("\tseq=0x%08x replay=%u flags=0x%08x ", m_sa2->sadb_x_sa2_sequence, m_sa->sadb_sa_replay, m_sa->sadb_sa_flags); /* state */ printf("state="); GETMSGSTR(str_state, m_sa->sadb_sa_state); printf("\n"); /* lifetime */ if (m_lftc != NULL) { time_t tmp_time = time(0); printf("\tcreated: %s", str_time(m_lftc->sadb_lifetime_addtime)); printf("\tcurrent: %s\n", str_time(tmp_time)); printf("\tdiff: %lu(s)", (u_long)(m_lftc->sadb_lifetime_addtime == 0 ? 0 : (tmp_time - m_lftc->sadb_lifetime_addtime))); printf("\thard: %lu(s)", (u_long)(m_lfth == NULL ? 0 : m_lfth->sadb_lifetime_addtime)); printf("\tsoft: %lu(s)\n", (u_long)(m_lfts == NULL ? 0 : m_lfts->sadb_lifetime_addtime)); printf("\tlast: %s", str_time(m_lftc->sadb_lifetime_usetime)); printf("\thard: %lu(s)", (u_long)(m_lfth == NULL ? 0 : m_lfth->sadb_lifetime_usetime)); printf("\tsoft: %lu(s)\n", (u_long)(m_lfts == NULL ? 0 : m_lfts->sadb_lifetime_usetime)); str_lifetime_byte(m_lftc, "current"); str_lifetime_byte(m_lfth, "hard"); str_lifetime_byte(m_lfts, "soft"); printf("\n"); printf("\tallocated: %lu", (unsigned long)m_lftc->sadb_lifetime_allocations); printf("\thard: %lu", (u_long)(m_lfth == NULL ? 0 : m_lfth->sadb_lifetime_allocations)); printf("\tsoft: %lu\n", (u_long)(m_lfts == NULL ? 0 : m_lfts->sadb_lifetime_allocations)); } printf("\tsadb_seq=%lu pid=%lu ", (u_long)m->sadb_msg_seq, (u_long)m->sadb_msg_pid); /* XXX DEBUG */ printf("refcnt=%u\n", m->sadb_msg_reserved); return; }
static void shortdump(struct sadb_msg *msg) { caddr_t mhp[SADB_EXT_MAX + 1]; char buf[NI_MAXHOST], pbuf[NI_MAXSERV]; struct sadb_sa *sa; struct sadb_address *saddr; struct sadb_lifetime *lts, *lth, *ltc; struct sockaddr *s; u_int t; time_t cur = time(0); pfkey_align(msg, mhp); pfkey_check(mhp); printf("%02lu%02lu", (u_long)(cur % 3600) / 60, (u_long)(cur % 60)); printf(" %-3s", STR_OR_ID(msg->sadb_msg_satype, satype)); if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) { printf(" %-1s", STR_OR_ID(sa->sadb_sa_state, sastate)); printf(" %08x", (uint32_t)ntohl(sa->sadb_sa_spi)); } else printf("%-1s %-8s", "?", "?"); lts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT]; lth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; ltc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT]; if (lts && lth && ltc) { if (ltc->sadb_lifetime_addtime == 0) t = (u_long)0; else t = (u_long)(cur - ltc->sadb_lifetime_addtime); if (t >= 1000) strlcpy(buf, " big/", sizeof(buf)); else snprintf(buf, sizeof(buf), " %3lu/", (u_long)t); printf("%s", buf); t = (u_long)lth->sadb_lifetime_addtime; if (t >= 1000) strlcpy(buf, "big", sizeof(buf)); else snprintf(buf, sizeof(buf), "%-3lu", (u_long)t); printf("%s", buf); } else printf(" ??\?/???"); /* backslash to avoid trigraph ??/ */ printf(" "); if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]) != NULL) { if (saddr->sadb_address_proto) printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto)); s = (struct sockaddr *)(saddr + 1); getnameinfo(s, sysdep_sa_len(s), buf, sizeof(buf), pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV); if (strcmp(pbuf, "0") != 0) printf("%s[%s]", buf, pbuf); else printf("%s", buf); } else printf("?"); printf(" -> "); if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]) != NULL) { if (saddr->sadb_address_proto) printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto)); s = (struct sockaddr *)(saddr + 1); getnameinfo(s, sysdep_sa_len(s), buf, sizeof(buf), pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV); if (strcmp(pbuf, "0") != 0) printf("%s[%s]", buf, pbuf); else printf("%s", buf); } else printf("?"); printf("\n"); }
static int postproc(struct sadb_msg *msg, int len) { #ifdef HAVE_PFKEY_POLICY_PRIORITY static int priority_support_check = 0; #endif if (msg->sadb_msg_errno != 0) { char inf[80]; const char *errmsg = NULL; if (f_mode == MODE_SCRIPT) snprintf(inf, sizeof(inf), "The result of line %d: ", lineno); else inf[0] = '\0'; switch (msg->sadb_msg_errno) { case ENOENT: switch (msg->sadb_msg_type) { case SADB_DELETE: case SADB_GET: case SADB_X_SPDDELETE: errmsg = "No entry"; break; case SADB_DUMP: errmsg = "No SAD entries"; break; case SADB_X_SPDDUMP: errmsg = "No SPD entries"; break; } break; default: errmsg = strerror(msg->sadb_msg_errno); } printf("%s%s.\n", inf, errmsg); return -1; } switch (msg->sadb_msg_type) { case SADB_GET: if (f_withports) pfkey_sadump_withports(msg); else pfkey_sadump(msg); break; case SADB_DUMP: /* filter out DEAD SAs */ if (!f_all) { caddr_t mhp[SADB_EXT_MAX + 1]; struct sadb_sa *sa; pfkey_align(msg, mhp); pfkey_check(mhp); if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) { if (sa->sadb_sa_state == SADB_SASTATE_DEAD) break; } } if (f_forever) { /* TODO: f_withports */ shortdump(msg); } else { if (f_withports) pfkey_sadump_withports(msg); else pfkey_sadump(msg); } break; case SADB_X_SPDGET: if (f_withports) pfkey_spdump_withports(msg); else pfkey_spdump(msg); break; case SADB_X_SPDDUMP: if (f_withports) pfkey_spdump_withports(msg); else pfkey_spdump(msg); break; #ifdef HAVE_PFKEY_POLICY_PRIORITY case SADB_X_SPDADD: if (last_msg_type == SADB_X_SPDADD && last_priority != 0 && msg->sadb_msg_pid == getpid() && !priority_support_check) { priority_support_check = 1; if (!verifypriority(msg)) printf("WARNING: Kernel does not support policy priorities\n"); } break; #endif } return 0; }
/* * Generate 'spi' array with SPIs matching 'satype', 'srcs', and 'dsts'. * Return value is dynamically generated array of SPIs, also number of * SPIs through num_spi pointer. * On any error, set *num_spi to 0 and return NULL. */ uint32_t * sendkeymsg_spigrep(unsigned int satype, struct addrinfo *srcs, struct addrinfo *dsts, int *num_spi) { struct sadb_msg msg, *m; char *buf; size_t len; ssize_t l; u_char rbuf[1024 * 32]; caddr_t mhp[SADB_EXT_MAX + 1]; struct sadb_address *saddr; struct sockaddr *s; struct addrinfo *a; struct sadb_sa *sa; uint32_t *spi = NULL; int max_spi = 0, fail = 0; *num_spi = 0; if (f_notreally) { return NULL; } { struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; if (setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { perror("setsockopt"); return NULL; } } msg.sadb_msg_version = PF_KEY_V2; msg.sadb_msg_type = SADB_DUMP; msg.sadb_msg_errno = 0; msg.sadb_msg_satype = satype; msg.sadb_msg_len = PFKEY_UNIT64(sizeof(msg)); msg.sadb_msg_reserved = 0; msg.sadb_msg_seq = 0; msg.sadb_msg_pid = getpid(); buf = (char *)&msg; len = sizeof(msg); if (f_verbose) { kdebug_sadb(&msg); printf("\n"); } if (f_hexdump) { int i; for (i = 0; i < len; i++) { if (i % 16 == 0) printf("%08x: ", i); printf("%02x ", buf[i] & 0xff); if (i % 16 == 15) printf("\n"); } if (len % 16) printf("\n"); } if ((l = send(so, buf, len, 0)) < 0) { perror("send"); return NULL; } m = (struct sadb_msg *)rbuf; do { if ((l = recv(so, rbuf, sizeof(rbuf), 0)) < 0) { perror("recv"); fail = 1; break; } if (PFKEY_UNUNIT64(m->sadb_msg_len) != l) { warnx("invalid keymsg length"); fail = 1; break; } if (f_verbose) { kdebug_sadb(m); printf("\n"); } if (m->sadb_msg_type != SADB_DUMP) { warnx("unexpected message type"); fail = 1; break; } if (m->sadb_msg_errno != 0) { warnx("error encountered"); fail = 1; break; } /* match satype */ if (m->sadb_msg_satype != satype) continue; pfkey_align(m, mhp); pfkey_check(mhp); /* match src */ saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; if (saddr == NULL) continue; s = (struct sockaddr *)(saddr + 1); for (a = srcs; a; a = a->ai_next) if (memcmp(a->ai_addr, s, a->ai_addrlen) == 0) break; if (a == NULL) continue; /* match dst */ saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; if (saddr == NULL) continue; s = (struct sockaddr *)(saddr + 1); for (a = dsts; a; a = a->ai_next) if (memcmp(a->ai_addr, s, a->ai_addrlen) == 0) break; if (a == NULL) continue; if (*num_spi >= max_spi) { max_spi += 512; spi = realloc(spi, max_spi * sizeof(uint32_t)); } sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; if (sa != NULL) spi[(*num_spi)++] = (uint32_t)ntohl(sa->sadb_sa_spi); m = (struct sadb_msg *)((caddr_t)m + PFKEY_UNUNIT64(m->sadb_msg_len)); if (f_verbose) { kdebug_sadb(m); printf("\n"); } } while (m->sadb_msg_seq); if (fail) { free(spi); *num_spi = 0; return NULL; } return spi; }