diff options
Diffstat (limited to 'ipsec-tools/src/setkey/setkey.c')
-rw-r--r-- | ipsec-tools/src/setkey/setkey.c | 1062 |
1 files changed, 1062 insertions, 0 deletions
diff --git a/ipsec-tools/src/setkey/setkey.c b/ipsec-tools/src/setkey/setkey.c new file mode 100644 index 00000000..c400faa6 --- /dev/null +++ b/ipsec-tools/src/setkey/setkey.c @@ -0,0 +1,1062 @@ +/* $NetBSD: setkey.c,v 1.14 2009/08/06 04:44:43 tteras Exp $ */ + +/* $KAME: setkey.c,v 1.36 2003/09/24 23:52:51 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <sys/sysctl.h> +#include <err.h> +#include <netinet/in.h> +#include <net/pfkeyv2.h> +#include PATH_IPSEC_H + +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <errno.h> +#include <netdb.h> +#include <fcntl.h> +#include <dirent.h> +#include <time.h> + +#ifdef HAVE_READLINE +#include <readline/readline.h> +#include <readline/history.h> +#endif + +#include "config.h" +#include "libpfkey.h" +#include "package_version.h" +#define extern /* so that variables in extern.h are not extern... */ +#include "extern.h" + +#define strlcpy(d,s,l) (strncpy(d,s,l), (d)[(l)-1] = '\0') + +void usage __P((int)); +int main __P((int, char **)); +int get_supported __P((void)); +void sendkeyshort __P((u_int)); +void promisc __P((void)); +int postproc __P((struct sadb_msg *, int)); +int verifypriority __P((struct sadb_msg *m)); +int fileproc __P((const char *)); +const char *numstr __P((int)); +void shortdump_hdr __P((void)); +void shortdump __P((struct sadb_msg *)); +static void printdate __P((void)); +static int32_t gmt2local __P((time_t)); +void stdin_loop __P((void)); + +#define MODE_SCRIPT 1 +#define MODE_CMDDUMP 2 +#define MODE_CMDFLUSH 3 +#define MODE_PROMISC 4 +#define MODE_STDIN 5 + +int so; + +int f_forever = 0; +int f_all = 0; +int f_verbose = 0; +int f_mode = 0; +int f_cmddump = 0; +int f_policy = 0; +int f_hexdump = 0; +int f_tflag = 0; +int f_notreally = 0; +int f_withports = 0; +#ifdef HAVE_POLICY_FWD +int f_rfcmode = 1; +#define RK_OPTS "rk" +#else +int f_rkwarn = 0; +#define RK_OPTS "" +static void rkwarn(void); +static void +rkwarn(void) +{ + if (!f_rkwarn) { + f_rkwarn = 1; + printf("warning: -r and -k options are not supported in this environment\n"); + } +} + +#endif +static time_t thiszone; + +void +usage(int only_version) +{ + printf("setkey @(#) %s (%s)\n", TOP_PACKAGE_STRING, TOP_PACKAGE_URL); + if (! only_version) { + printf("usage: setkey [-v" RK_OPTS "] file ...\n"); + printf(" setkey [-nv" RK_OPTS "] -c\n"); + printf(" setkey [-nv" RK_OPTS "] -f filename\n"); + printf(" setkey [-Palpv" RK_OPTS "] -D\n"); + printf(" setkey [-Pv] -F\n"); + printf(" setkey [-H] -x\n"); + printf(" setkey [-V] [-h]\n"); + } + exit(1); +} + +int +main(argc, argv) + int argc; + char **argv; +{ + FILE *fp = stdin; + int c; + + if (argc == 1) { + usage(0); + /* NOTREACHED */ + } + + thiszone = gmt2local(0); + + while ((c = getopt(argc, argv, "acdf:HlnvxDFPphVrk?")) != -1) { + switch (c) { + case 'c': + f_mode = MODE_STDIN; +#ifdef HAVE_READLINE + /* disable filename completion */ + rl_bind_key('\t', rl_insert); +#endif + break; + case 'f': + f_mode = MODE_SCRIPT; + if ((fp = fopen(optarg, "r")) == NULL) { + err(1, "fopen"); + /*NOTREACHED*/ + } + break; + case 'D': + f_mode = MODE_CMDDUMP; + break; + case 'F': + f_mode = MODE_CMDFLUSH; + break; + case 'a': + f_all = 1; + break; + case 'l': + f_forever = 1; + break; + case 'n': + f_notreally = 1; + break; +#ifdef __NetBSD__ + case 'h': +#endif + case 'H': + f_hexdump = 1; + break; + case 'x': + f_mode = MODE_PROMISC; + f_tflag++; + break; + case 'P': + f_policy = 1; + break; + case 'p': + f_withports = 1; + break; + case 'v': + f_verbose = 1; + break; + case 'r': +#ifdef HAVE_POLICY_FWD + f_rfcmode = 1; +#else + rkwarn(); +#endif + break; + case 'k': +#ifdef HAVE_POLICY_FWD + f_rfcmode = 0; +#else + rkwarn(); +#endif + break; + case 'V': + usage(1); + break; + /*NOTREACHED*/ +#ifndef __NetBSD__ + case 'h': +#endif + case '?': + default: + usage(0); + /*NOTREACHED*/ + } + } + + argc -= optind; + argv += optind; + + if (argc > 0) { + while (argc--) + if (fileproc(*argv++) < 0) { + err(1, "%s", argv[-1]); + /*NOTREACHED*/ + } + exit(0); + } + + so = pfkey_open(); + if (so < 0) { + perror("pfkey_open"); + exit(1); + } + + switch (f_mode) { + case MODE_CMDDUMP: + sendkeyshort(f_policy ? SADB_X_SPDDUMP : SADB_DUMP); + break; + case MODE_CMDFLUSH: + sendkeyshort(f_policy ? SADB_X_SPDFLUSH: SADB_FLUSH); + break; + case MODE_SCRIPT: + if (get_supported() < 0) { + errx(1, "%s", ipsec_strerror()); + /*NOTREACHED*/ + } + if (parse(&fp)) + exit (1); + break; + case MODE_STDIN: + if (get_supported() < 0) { + errx(1, "%s", ipsec_strerror()); + /*NOTREACHED*/ + } + stdin_loop(); + break; + case MODE_PROMISC: + promisc(); + /*NOTREACHED*/ + default: + usage(0); + /*NOTREACHED*/ + } + + exit(0); +} + +int +get_supported() +{ + + if (pfkey_send_register(so, SADB_SATYPE_UNSPEC) < 0) + return -1; + + if (pfkey_recv_register(so) < 0) + return -1; + + return (0); +} + +void +stdin_loop() +{ + char line[1024], *semicolon, *comment; + size_t linelen = 0; + + memset (line, 0, sizeof(line)); + + parse_init(); + while (1) { +#ifdef HAVE_READLINE + char *rbuf; + rbuf = readline (""); + if (! rbuf) + break; +#else + char rbuf[1024]; + rbuf[0] = '\0'; + if (fgets(rbuf, sizeof(rbuf), stdin) == NULL) + break; + if (rbuf[strlen(rbuf)-1] == '\n') + rbuf[strlen(rbuf)-1] = '\0'; +#endif + comment = strchr(rbuf, '#'); + if (comment) + *comment = '\0'; + + if (!rbuf[0]) + continue; + + linelen += snprintf (&line[linelen], sizeof(line) - linelen, + "%s%s", linelen > 0 ? " " : "", rbuf); + + semicolon = strchr(line, ';'); + while (semicolon) { + char saved_char = *++semicolon; + *semicolon = '\0'; +#ifdef HAVE_READLINE + add_history (line); +#endif + +#ifdef HAVE_PFKEY_POLICY_PRIORITY + last_msg_type = -1; /* invalid message type */ +#endif + + parse_string (line); + if (exit_now) + return; + if (saved_char) { + *semicolon = saved_char; + linelen = strlen (semicolon); + memmove (line, semicolon, linelen + 1); + semicolon = strchr(line, ';'); + } + else { + semicolon = NULL; + linelen = 0; + } + } + } +} + +void +sendkeyshort(type) + u_int type; +{ + struct sadb_msg msg; + + msg.sadb_msg_version = PF_KEY_V2; + msg.sadb_msg_type = type; + msg.sadb_msg_errno = 0; + msg.sadb_msg_satype = SADB_SATYPE_UNSPEC; + msg.sadb_msg_len = PFKEY_UNIT64(sizeof(msg)); + msg.sadb_msg_reserved = 0; + msg.sadb_msg_seq = 0; + msg.sadb_msg_pid = getpid(); + + sendkeymsg((char *)&msg, sizeof(msg)); + + return; +} + +void +promisc() +{ + struct sadb_msg msg; + u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */ + ssize_t l; + + msg.sadb_msg_version = PF_KEY_V2; + msg.sadb_msg_type = SADB_X_PROMISC; + msg.sadb_msg_errno = 0; + msg.sadb_msg_satype = 1; + msg.sadb_msg_len = PFKEY_UNIT64(sizeof(msg)); + msg.sadb_msg_reserved = 0; + msg.sadb_msg_seq = 0; + msg.sadb_msg_pid = getpid(); + + if ((l = send(so, &msg, sizeof(msg), 0)) < 0) { + err(1, "send"); + /*NOTREACHED*/ + } + + while (1) { + struct sadb_msg *base; + + if ((l = recv(so, rbuf, sizeof(*base), MSG_PEEK)) < 0) { + err(1, "recv"); + /*NOTREACHED*/ + } + + if (l != sizeof(*base)) + continue; + + base = (struct sadb_msg *)rbuf; + if ((l = recv(so, rbuf, PFKEY_UNUNIT64(base->sadb_msg_len), + 0)) < 0) { + err(1, "recv"); + /*NOTREACHED*/ + } + printdate(); + if (f_hexdump) { + int i; + for (i = 0; i < l; i++) { + if (i % 16 == 0) + printf("%08x: ", i); + printf("%02x ", rbuf[i] & 0xff); + if (i % 16 == 15) + printf("\n"); + } + if (l % 16) + printf("\n"); + } + /* adjust base pointer for promisc mode */ + if (base->sadb_msg_type == SADB_X_PROMISC) { + if ((ssize_t)sizeof(*base) < l) + base++; + else + base = NULL; + } + if (base) { + kdebug_sadb(base); + printf("\n"); + fflush(stdout); + } + } +} + +/* 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. + */ +u_int32_t * +sendkeymsg_spigrep(satype, srcs, dsts, num_spi) + 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; + u_int32_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(u_int32_t)); + } + + sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; + if (sa != NULL) + spi[(*num_spi)++] = (u_int32_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; +} + +int +sendkeymsg(buf, len) + char *buf; + size_t len; +{ + u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */ + ssize_t l; + struct sadb_msg *msg; + + if (f_notreally) { + goto end; + } + + { + struct timeval tv; + tv.tv_sec = 1; + tv.tv_usec = 0; + if (setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { + perror("setsockopt"); + goto end; + } + } + + if (f_forever) + shortdump_hdr(); +again: + if (f_verbose) { + kdebug_sadb((struct sadb_msg *)buf); + 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"); + goto end; + } + + msg = (struct sadb_msg *)rbuf; + do { + if ((l = recv(so, rbuf, sizeof(rbuf), 0)) < 0) { + perror("recv"); + goto end; + } + + if (PFKEY_UNUNIT64(msg->sadb_msg_len) != l) { + warnx("invalid keymsg length"); + break; + } + + if (f_verbose) { + kdebug_sadb(msg); + printf("\n"); + } + if (postproc(msg, l) < 0) + break; + } while (msg->sadb_msg_errno || msg->sadb_msg_seq); + + if (f_forever) { + fflush(stdout); + sleep(1); + goto again; + } + +end: + return (0); +} + +int +postproc(msg, len) + 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); + } + msg = (struct sadb_msg *)((caddr_t)msg + + PFKEY_UNUNIT64(msg->sadb_msg_len)); + if (f_verbose) { + kdebug_sadb((struct sadb_msg *)msg); + printf("\n"); + } + 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); + if (msg->sadb_msg_seq == 0) break; + msg = (struct sadb_msg *)((caddr_t)msg + + PFKEY_UNUNIT64(msg->sadb_msg_len)); + if (f_verbose) { + kdebug_sadb((struct sadb_msg *)msg); + printf("\n"); + } + 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); +} + +#ifdef HAVE_PFKEY_POLICY_PRIORITY +int +verifypriority(m) + 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; +} +#endif + +int +fileproc(filename) + const char *filename; +{ + int fd; + ssize_t len, l; + u_char *p, *ep; + struct sadb_msg *msg; + u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */ + + fd = open(filename, O_RDONLY); + if (fd < 0) + return -1; + + l = 0; + while (1) { + len = read(fd, rbuf + l, sizeof(rbuf) - l); + if (len < 0) { + close(fd); + return -1; + } else if (len == 0) + break; + l += len; + } + + if (l < sizeof(struct sadb_msg)) { + close(fd); + errno = EINVAL; + return -1; + } + close(fd); + + p = rbuf; + ep = rbuf + l; + + while (p < ep) { + msg = (struct sadb_msg *)p; + len = PFKEY_UNUNIT64(msg->sadb_msg_len); + postproc(msg, len); + p += len; + } + + return (0); +} + + +/*------------------------------------------------------------*/ +static const char *satype[] = { + NULL, NULL, "ah", "esp" +}; +static const char *sastate[] = { + "L", "M", "D", "d" +}; +static const char *ipproto[] = { +/*0*/ "ip", "icmp", "igmp", "ggp", "ip4", + NULL, "tcp", NULL, "egp", NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, + NULL, NULL, "udp", NULL, NULL, +/*20*/ NULL, NULL, "idp", NULL, NULL, + NULL, NULL, NULL, NULL, "tp", +/*30*/ NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, +/*40*/ NULL, "ip6", NULL, "rt6", "frag6", + NULL, "rsvp", "gre", NULL, NULL, +/*50*/ "esp", "ah", NULL, NULL, NULL, + NULL, NULL, NULL, "icmp6", "none", +/*60*/ "dst6", +}; + +#define STR_OR_ID(x, tab) \ + (((x) < sizeof(tab)/sizeof(tab[0]) && tab[(x)]) ? tab[(x)] : numstr(x)) + +const char * +numstr(x) + int x; +{ + static char buf[20]; + snprintf(buf, sizeof(buf), "#%d", x); + return buf; +} + +void +shortdump_hdr() +{ + printf("%-4s %-3s %-1s %-8s %-7s %s -> %s\n", + "time", "p", "s", "spi", "ltime", "src", "dst"); +} + +void +shortdump(msg) + 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", (u_int32_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"); +} + +/* From: tcpdump(1):gmt2local.c and util.c */ +/* + * Print the timestamp + */ +static void +printdate() +{ + struct timeval tp; + int s; + + if (gettimeofday(&tp, NULL) == -1) { + perror("gettimeofday"); + return; + } + + if (f_tflag == 1) { + /* Default */ + s = (tp.tv_sec + thiszone ) % 86400; + (void)printf("%02d:%02d:%02d.%06u ", + s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tp.tv_usec); + } else if (f_tflag > 1) { + /* Unix timeval style */ + (void)printf("%u.%06u ", + (u_int32_t)tp.tv_sec, (u_int32_t)tp.tv_usec); + } + + printf("\n"); +} + +/* + * Returns the difference between gmt and local time in seconds. + * Use gmtime() and localtime() to keep things simple. + */ +int32_t +gmt2local(time_t t) +{ + register int dt, dir; + register struct tm *gmt, *loc; + struct tm sgmt; + + if (t == 0) + t = time(NULL); + gmt = &sgmt; + *gmt = *gmtime(&t); + loc = localtime(&t); + dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 + + (loc->tm_min - gmt->tm_min) * 60; + + /* + * If the year or julian day is different, we span 00:00 GMT + * and must add or subtract a day. Check the year first to + * avoid problems when the julian day wraps. + */ + dir = loc->tm_year - gmt->tm_year; + if (dir == 0) + dir = loc->tm_yday - gmt->tm_yday; + dt += dir * 24 * 60 * 60; + + return (dt); +} |