1102 lines
21 KiB
C
1102 lines
21 KiB
C
/* $KAME: kmpstat.c,v 1.29 2001/08/02 12:16:05 itojun Exp $ */
|
|
|
|
/*
|
|
* Copyright (C) 1995, 1996, 1997, and 1998 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.
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/param.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
|
|
#include <netinet/in.h>
|
|
#include <net/pfkeyv2.h>
|
|
#include <netkey/keydb.h>
|
|
#include <netkey/key_var.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#if TIME_WITH_SYS_TIME
|
|
# include <sys/time.h>
|
|
# include <time.h>
|
|
#else
|
|
# if HAVE_SYS_TIME_H
|
|
# include <sys/time.h>
|
|
# else
|
|
# include <time.h>
|
|
# endif
|
|
#endif
|
|
#include <netdb.h>
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#include <err.h>
|
|
|
|
#include "libpfkey.h"
|
|
|
|
#include "var.h"
|
|
#include "misc.h"
|
|
#include "vmbuf.h"
|
|
#include "plog.h"
|
|
#include "debug.h"
|
|
|
|
#include "schedule.h"
|
|
#include "isakmp_var.h"
|
|
#include "isakmp.h"
|
|
#include "oakley.h"
|
|
#include "handler.h"
|
|
#include "pfkey.h"
|
|
#include "admin.h"
|
|
#include "admin_var.h"
|
|
|
|
static void usage __P((void));
|
|
static void com_init __P((void));
|
|
static int com_send __P((vchar_t *));
|
|
static vchar_t *com_recv __P((void));
|
|
|
|
static vchar_t *get_combuf __P((int, char **));
|
|
static vchar_t *f_reload __P((int, char **));
|
|
static vchar_t *f_getsched __P((int, char **));
|
|
static vchar_t *f_getsa __P((int, char **));
|
|
static vchar_t *f_flushsa __P((int, char **));
|
|
static vchar_t *f_deletesa __P((int, char **));
|
|
static vchar_t *f_exchangesa __P((int, char **));
|
|
|
|
struct cmd_tag {
|
|
vchar_t *(*func) __P((int, char **));
|
|
int cmd;
|
|
char *str;
|
|
} cmdtab[] = {
|
|
{ f_reload, ADMIN_RELOAD_CONF, "reload-config" },
|
|
{ f_reload, ADMIN_RELOAD_CONF, "rc" },
|
|
{ f_getsched, ADMIN_SHOW_SCHED, "show-schedule" },
|
|
{ f_getsched, ADMIN_SHOW_SCHED, "sc" },
|
|
{ f_getsa, ADMIN_SHOW_SA, "show-sa" },
|
|
{ f_getsa, ADMIN_SHOW_SA, "ss" },
|
|
{ f_flushsa, ADMIN_FLUSH_SA, "flush-sa" },
|
|
{ f_flushsa, ADMIN_FLUSH_SA, "fs" },
|
|
{ f_deletesa, ADMIN_DELETE_SA, "delete-sa" },
|
|
{ f_deletesa, ADMIN_DELETE_SA, "ds" },
|
|
{ f_exchangesa, ADMIN_ESTABLISH_SA, "establish-sa" },
|
|
{ f_exchangesa, ADMIN_ESTABLISH_SA, "es" },
|
|
{ NULL, 0, NULL },
|
|
};
|
|
|
|
static int get_proto __P((char *));
|
|
static vchar_t *get_index __P((int, char **));
|
|
static int get_family __P((char *));
|
|
static vchar_t *get_comindexes __P((int, int, char **));
|
|
static int get_comindex __P((char *, char **, char **, char **));
|
|
static struct sockaddr *get_sockaddr __P((int, char *, char *));
|
|
static int get_ulproto __P((char *));
|
|
|
|
struct proto_tag {
|
|
int proto;
|
|
char *str;
|
|
} prototab[] = {
|
|
{ ADMIN_PROTO_ISAKMP, "isakmp" },
|
|
{ ADMIN_PROTO_IPSEC, "ipsec" },
|
|
{ ADMIN_PROTO_AH, "ah" },
|
|
{ ADMIN_PROTO_ESP, "esp" },
|
|
{ ADMIN_PROTO_INTERNAL, "internal" },
|
|
{ 0, NULL },
|
|
};
|
|
|
|
struct ulproto_tag {
|
|
int ul_proto;
|
|
char *str;
|
|
} ulprototab[] = {
|
|
{ 0, "any" },
|
|
{ IPPROTO_ICMP, "icmp" },
|
|
{ IPPROTO_TCP, "tcp" },
|
|
{ IPPROTO_UDP, "udp" },
|
|
{ 0, NULL },
|
|
};
|
|
|
|
int so;
|
|
|
|
static char _addr1_[NI_MAXHOST], _addr2_[NI_MAXHOST];
|
|
|
|
char *pname;
|
|
int long_format = 0;
|
|
u_int32_t loglevel = 4;
|
|
|
|
void dump_isakmp_sa __P((char *, int));
|
|
void dump_internal __P((char *, int));
|
|
char *pindex_isakmp __P((isakmp_index *));
|
|
void print_schedule __P((caddr_t, int));
|
|
char * fixed_addr __P((char *, char *, int));
|
|
|
|
static void
|
|
usage()
|
|
{
|
|
printf(
|
|
"Usage:\n"
|
|
" %s reload-config\n"
|
|
" %s [-l [-l]] show-sa [protocol]\n"
|
|
" %s flush-sa [protocol]\n"
|
|
" %s delete-sa <saopts>\n"
|
|
" %s establish-sa <saopts>\n"
|
|
"\n"
|
|
" <protocol>: \"isakmp\", \"esp\" or \"ah\".\n"
|
|
" In the case of \"show-sa\" or \"flush-sa\", you can use \"ipsec\".\n"
|
|
"\n"
|
|
" <saopts>: \"isakmp\" <family> <src> <dst>\n"
|
|
" : {\"esp\",\"ah\"} <family> <src/prefixlen/port> <dst/prefixlen/port>\n"
|
|
" <ul_proto>\n"
|
|
" <family>: \"inet\" or \"inet6\"\n"
|
|
" <ul_proto>: \"icmp\", \"tcp\", \"udp\" or \"any\"\n",
|
|
pname, pname, pname, pname, pname);
|
|
}
|
|
|
|
int
|
|
main(ac, av)
|
|
int ac;
|
|
char **av;
|
|
{
|
|
extern char *optarg;
|
|
extern int optind;
|
|
vchar_t *combuf;
|
|
int c;
|
|
|
|
pname = *av;
|
|
|
|
while ((c = getopt(ac, av, "ld")) != -1) {
|
|
switch(c) {
|
|
case 'l':
|
|
long_format++;
|
|
break;
|
|
|
|
case 'd':
|
|
loglevel++;
|
|
break;
|
|
|
|
default:
|
|
usage();
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
ac -= optind;
|
|
av += optind;
|
|
|
|
combuf = get_combuf(ac, av);
|
|
if (!combuf)
|
|
err(1, "kmpstat");
|
|
|
|
if (loglevel)
|
|
hexdump(combuf, ((struct admin_com *)combuf)->ac_len);
|
|
|
|
com_init();
|
|
|
|
if (com_send(combuf) < 0)
|
|
goto bad;
|
|
|
|
vfree(combuf);
|
|
|
|
combuf = com_recv();
|
|
if (!combuf)
|
|
goto bad;
|
|
|
|
exit(0);
|
|
|
|
bad:
|
|
exit(1);
|
|
}
|
|
|
|
static void
|
|
com_init()
|
|
{
|
|
struct sockaddr_un name;
|
|
|
|
memset(&name, 0, sizeof(name));
|
|
name.sun_family = AF_UNIX;
|
|
snprintf(name.sun_path, sizeof(name.sun_path),
|
|
"%s", PORT_ADMIN);
|
|
|
|
so = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
if (so < 0)
|
|
err(1, "socket");
|
|
|
|
if (connect(so, (struct sockaddr *)&name, sizeof(name)) < 0) {
|
|
(void)close(so);
|
|
err(1, "connect");
|
|
}
|
|
}
|
|
|
|
static int
|
|
com_send(combuf)
|
|
vchar_t *combuf;
|
|
{
|
|
int len;
|
|
|
|
if ((len = send(so, combuf->v, combuf->l, 0)) < 0){
|
|
perror("send");
|
|
(void)close(so);
|
|
return -1;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
static vchar_t *
|
|
com_recv()
|
|
{
|
|
vchar_t *combuf = NULL;
|
|
struct admin_com h, *com;
|
|
caddr_t buf;
|
|
int len;
|
|
|
|
/* receive by PEEK */
|
|
len = recv(so, &h, sizeof(h), MSG_PEEK);
|
|
if (len == -1)
|
|
goto bad;
|
|
|
|
/* sanity check */
|
|
if (len < sizeof(h))
|
|
return NULL;
|
|
if (len == 0)
|
|
goto bad;
|
|
|
|
/* error ? */
|
|
if (h.ac_errno) {
|
|
errno = h.ac_errno;
|
|
goto bad;
|
|
}
|
|
|
|
/* allocate buffer */
|
|
combuf = vmalloc(h.ac_len);
|
|
if (combuf == NULL)
|
|
goto bad;
|
|
|
|
/* read real message */
|
|
{
|
|
int l = 0;
|
|
caddr_t p = combuf->v;
|
|
while (l < combuf->l) {
|
|
if ((len = recv(so, p, h.ac_len, 0)) < 0) {
|
|
perror("recv");
|
|
goto bad;
|
|
}
|
|
l += len;
|
|
p += len;
|
|
}
|
|
}
|
|
|
|
com = (struct admin_com *)combuf->v;
|
|
len = com->ac_len - sizeof(*com);
|
|
buf = combuf->v + sizeof(*com);
|
|
|
|
switch (com->ac_cmd) {
|
|
case ADMIN_SHOW_SCHED:
|
|
print_schedule(buf, len);
|
|
break;
|
|
|
|
case ADMIN_SHOW_SA:
|
|
{
|
|
switch (com->ac_proto) {
|
|
case ADMIN_PROTO_ISAKMP:
|
|
dump_isakmp_sa(buf, len);
|
|
break;
|
|
case ADMIN_PROTO_IPSEC:
|
|
case ADMIN_PROTO_AH:
|
|
case ADMIN_PROTO_ESP:
|
|
{
|
|
struct sadb_msg *msg = (struct sadb_msg *)buf;
|
|
|
|
switch (msg->sadb_msg_errno) {
|
|
case ENOENT:
|
|
switch (msg->sadb_msg_type) {
|
|
case SADB_DELETE:
|
|
case SADB_GET:
|
|
printf("No entry.\n");
|
|
break;
|
|
case SADB_DUMP:
|
|
printf("No SAD entries.\n");
|
|
break;
|
|
}
|
|
break;
|
|
case 0:
|
|
while (1) {
|
|
pfkey_sadump(msg);
|
|
if (msg->sadb_msg_seq == 0)
|
|
break;
|
|
msg = (struct sadb_msg *)((caddr_t)msg +
|
|
PFKEY_UNUNIT64(msg->sadb_msg_len));
|
|
}
|
|
break;
|
|
default:
|
|
printf("%s.\n", strerror(msg->sadb_msg_errno));
|
|
}
|
|
}
|
|
break;
|
|
case ADMIN_PROTO_INTERNAL:
|
|
dump_internal(buf, len);
|
|
break;
|
|
default:
|
|
printf("Invalid proto [%d]\n", com->ac_proto);
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
default:
|
|
/* IGNORE */
|
|
}
|
|
|
|
(void)close(so);
|
|
return combuf;
|
|
|
|
bad:
|
|
(void)close(so);
|
|
return NULL;
|
|
}
|
|
|
|
/* %%% */
|
|
/*
|
|
* return command buffer.
|
|
*/
|
|
static vchar_t *
|
|
get_combuf(ac, av)
|
|
int ac;
|
|
char **av;
|
|
{
|
|
struct cmd_tag *cp;
|
|
|
|
if (ac == 0) {
|
|
usage();
|
|
exit(0);
|
|
}
|
|
|
|
/* checking the string of command. */
|
|
for (cp = &cmdtab[0]; cp->str; cp++) {
|
|
if (strcmp(*av, cp->str) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
if (!cp->str) {
|
|
printf("Invalid command [%s]\n", *av);
|
|
errno = EINVAL;
|
|
return NULL;
|
|
}
|
|
|
|
ac--;
|
|
av++;
|
|
return (cp->func)(ac, av);
|
|
}
|
|
|
|
static vchar_t *
|
|
f_reload(ac, av)
|
|
int ac;
|
|
char **av;
|
|
{
|
|
vchar_t *buf;
|
|
struct admin_com *head;
|
|
|
|
buf = vmalloc(sizeof(*head));
|
|
if (buf == NULL)
|
|
errx(1, "not enough core");
|
|
|
|
head = (struct admin_com *)buf->v;
|
|
head->ac_len = buf->l;
|
|
head->ac_cmd = ADMIN_RELOAD_CONF;
|
|
head->ac_errno = 0;
|
|
head->ac_proto = 0;
|
|
|
|
return buf;
|
|
}
|
|
|
|
static vchar_t *
|
|
f_getsched(ac, av)
|
|
int ac;
|
|
char **av;
|
|
{
|
|
vchar_t *buf;
|
|
struct admin_com *head;
|
|
|
|
buf = vmalloc(sizeof(*head));
|
|
if (buf == NULL)
|
|
errx(1, "not enough core");
|
|
|
|
head = (struct admin_com *)buf->v;
|
|
head->ac_len = buf->l;
|
|
head->ac_cmd = ADMIN_SHOW_SCHED;
|
|
head->ac_errno = 0;
|
|
head->ac_proto = 0;
|
|
|
|
return buf;
|
|
}
|
|
|
|
static vchar_t *
|
|
f_getsa(ac, av)
|
|
int ac;
|
|
char **av;
|
|
{
|
|
vchar_t *buf;
|
|
struct admin_com *head;
|
|
int proto;
|
|
|
|
/* need protocol */
|
|
if (ac != 1)
|
|
errx(1, "insufficient arguments");
|
|
proto = get_proto(*av);
|
|
if (proto == -1)
|
|
errx(1, "unknown protocol %s", *av);
|
|
|
|
buf = vmalloc(sizeof(*head));
|
|
if (buf == NULL)
|
|
errx(1, "not enough core");
|
|
|
|
head = (struct admin_com *)buf->v;
|
|
head->ac_len = buf->l;
|
|
head->ac_cmd = ADMIN_SHOW_SA;
|
|
head->ac_errno = 0;
|
|
head->ac_proto = proto;
|
|
|
|
return buf;
|
|
}
|
|
|
|
static vchar_t *
|
|
f_flushsa(ac, av)
|
|
int ac;
|
|
char **av;
|
|
{
|
|
vchar_t *buf;
|
|
struct admin_com *head;
|
|
int proto;
|
|
|
|
/* need protocol */
|
|
if (ac != 1)
|
|
errx(1, "insufficient arguments");
|
|
proto = get_proto(*av);
|
|
if (proto == -1)
|
|
errx(1, "unknown protocol %s", *av);
|
|
|
|
buf = vmalloc(sizeof(*head));
|
|
if (buf == NULL)
|
|
errx(1, "not enough core");
|
|
|
|
head = (struct admin_com *)buf->v;
|
|
head->ac_len = buf->l;
|
|
head->ac_cmd = ADMIN_FLUSH_SA;
|
|
head->ac_errno = 0;
|
|
head->ac_proto = proto;
|
|
|
|
return buf;
|
|
}
|
|
|
|
static vchar_t *
|
|
f_deletesa(ac, av)
|
|
int ac;
|
|
char **av;
|
|
{
|
|
vchar_t *buf, *index;
|
|
struct admin_com *head;
|
|
int proto;
|
|
|
|
/* need protocol */
|
|
if (ac < 1)
|
|
errx(1, "insufficient arguments");
|
|
proto = get_proto(*av);
|
|
if (proto == -1)
|
|
errx(1, "unknown protocol %s", *av);
|
|
|
|
/* get index(es) */
|
|
av++;
|
|
ac--;
|
|
switch (proto) {
|
|
case ADMIN_PROTO_ISAKMP:
|
|
index = get_index(ac, av);
|
|
if (index == NULL)
|
|
return NULL;
|
|
break;
|
|
case ADMIN_PROTO_AH:
|
|
case ADMIN_PROTO_ESP:
|
|
index = get_index(ac, av);
|
|
if (index == NULL)
|
|
return NULL;
|
|
break;
|
|
default:
|
|
errno = EPROTONOSUPPORT;
|
|
return NULL;
|
|
}
|
|
|
|
buf = vmalloc(sizeof(*head) + index->l);
|
|
if (buf == NULL)
|
|
return NULL;
|
|
|
|
head = (struct admin_com *)buf->v;
|
|
head->ac_len = buf->l + index->l;
|
|
head->ac_cmd = ADMIN_DELETE_SA;
|
|
head->ac_errno = 0;
|
|
head->ac_proto = proto;
|
|
|
|
return buf;
|
|
}
|
|
|
|
static vchar_t *
|
|
f_exchangesa(ac, av)
|
|
int ac;
|
|
char **av;
|
|
{
|
|
vchar_t *buf, *index;
|
|
struct admin_com *head;
|
|
int proto;
|
|
|
|
/* need protocol */
|
|
if (ac < 1)
|
|
errx(1, "insufficient arguments");
|
|
if ((proto = get_proto(*av)) == -1)
|
|
errx(1, "unknown protocol %s", *av);
|
|
|
|
/* get index(es) */
|
|
av++;
|
|
ac--;
|
|
switch (proto) {
|
|
case ADMIN_PROTO_ISAKMP:
|
|
index = get_index(ac, av);
|
|
if (index == NULL)
|
|
return NULL;
|
|
break;
|
|
case ADMIN_PROTO_AH:
|
|
case ADMIN_PROTO_ESP:
|
|
index = get_index(ac, av);
|
|
if (index == NULL)
|
|
return NULL;
|
|
break;
|
|
default:
|
|
errno = EPROTONOSUPPORT;
|
|
return NULL;
|
|
}
|
|
|
|
buf = vmalloc(sizeof(*head) + index->l);
|
|
if (buf == NULL)
|
|
return NULL;
|
|
|
|
head = (struct admin_com *)buf->v;
|
|
head->ac_len = buf->l + index->l;
|
|
head->ac_cmd = ADMIN_DELETE_SA;
|
|
head->ac_errno = 0;
|
|
head->ac_proto = proto;
|
|
|
|
return buf;
|
|
}
|
|
|
|
static int
|
|
get_proto(str)
|
|
char *str;
|
|
{
|
|
struct proto_tag *cp;
|
|
|
|
if (str == NULL) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
/* checking the string of command. */
|
|
for (cp = &prototab[0]; cp->str; cp++) {
|
|
if (strcmp(str, cp->str) == 0)
|
|
return cp->proto;
|
|
}
|
|
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
static vchar_t *
|
|
get_index(ac, av)
|
|
int ac;
|
|
char **av;
|
|
{
|
|
int family;
|
|
|
|
if (ac != 3) {
|
|
errno = EINVAL;
|
|
return NULL;
|
|
}
|
|
|
|
/* checking the string of family */
|
|
family = get_family(*av);
|
|
if (family == -1)
|
|
return NULL;
|
|
av++;
|
|
|
|
return get_comindexes(family, ac, av);
|
|
}
|
|
|
|
static int
|
|
get_family(str)
|
|
char *str;
|
|
{
|
|
if (strcmp("inet", str) == 0)
|
|
return AF_INET;
|
|
#ifdef INET6
|
|
else if (strcmp("inet6", str) == 0)
|
|
return AF_INET6;
|
|
#endif
|
|
errno = EAFNOSUPPORT;
|
|
return -1;
|
|
}
|
|
|
|
static vchar_t *
|
|
get_comindexes(family, ac, av)
|
|
int family;
|
|
int ac;
|
|
char **av;
|
|
{
|
|
vchar_t *buf;
|
|
struct admin_com_indexes *ci;
|
|
char *p_name = NULL, *p_port = NULL;
|
|
char *p_prefs = NULL, *p_prefd = NULL;
|
|
struct sockaddr *src = NULL, *dst = NULL;
|
|
int ulproto;
|
|
|
|
if (ac != 2) {
|
|
errno = EINVAL;
|
|
return NULL;
|
|
}
|
|
|
|
if (get_comindex(*av, &p_name, &p_port, &p_prefs) == -1)
|
|
goto bad;
|
|
src = get_sockaddr(family, p_name, p_port);
|
|
if (p_name) {
|
|
racoon_free(p_name);
|
|
p_name = NULL;
|
|
}
|
|
if (p_port) {
|
|
racoon_free(p_port);
|
|
p_port = NULL;
|
|
}
|
|
if (src == NULL)
|
|
goto bad;
|
|
av++;
|
|
if (get_comindex(*av, &p_name, &p_port, &p_prefd) == -1)
|
|
goto bad;
|
|
dst = get_sockaddr(family, p_name, p_port);
|
|
if (dst == NULL)
|
|
goto bad;
|
|
|
|
buf = vmalloc(sizeof(*ci));
|
|
if (buf == NULL)
|
|
goto bad;
|
|
|
|
av++;
|
|
ulproto = get_ulproto(*av);
|
|
if (ulproto == -1)
|
|
goto bad;
|
|
|
|
ci = (struct admin_com_indexes *)buf;
|
|
ci->prefs = (u_int8_t)atoi(p_prefs); /* XXX should be handled error. */
|
|
ci->prefd = (u_int8_t)atoi(p_prefd); /* XXX should be handled error. */
|
|
ci->ul_proto = ulproto;
|
|
memcpy(&ci->src, src, src->sa_len);
|
|
memcpy(&ci->dst, dst, dst->sa_len);
|
|
|
|
if (p_name)
|
|
|
|
return buf;
|
|
|
|
bad:
|
|
if (p_name)
|
|
racoon_free(p_name);
|
|
if (p_port)
|
|
racoon_free(p_port);
|
|
if (p_prefs);
|
|
racoon_free(p_prefs);
|
|
if (p_prefd);
|
|
racoon_free(p_prefd);
|
|
return NULL;
|
|
}
|
|
|
|
static int
|
|
get_comindex(str, name, port, pref)
|
|
char *str, **name, **port, **pref;
|
|
{
|
|
char *p;
|
|
|
|
*name = *port = *pref = NULL;
|
|
|
|
*name = strdup(str);
|
|
p = strpbrk(*name, "/[");
|
|
if (p != NULL) {
|
|
if (*(p + 1) == '\0')
|
|
goto bad;
|
|
if (*p == '/') {
|
|
*p = '\0';
|
|
*pref = strdup(p + 1);
|
|
p = strchr(*pref, '[');
|
|
if (p != NULL) {
|
|
if (*(p + 1) == '\0')
|
|
goto bad;
|
|
*p = '\0';
|
|
*port = strdup(p + 1);
|
|
p = strchr(*pref, ']');
|
|
if (p == NULL)
|
|
goto bad;
|
|
*p = '\0';
|
|
}
|
|
} else if (*p == '[') {
|
|
*p = '\0';
|
|
*port = strdup(p + 1);
|
|
p = strchr(*pref, ']');
|
|
if (p == NULL)
|
|
goto bad;
|
|
*p = '\0';
|
|
} else {
|
|
/* XXX */
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
bad:
|
|
if (*name)
|
|
racoon_free(*name);
|
|
if (*port)
|
|
racoon_free(*port);
|
|
if (*pref)
|
|
racoon_free(*pref);
|
|
*name = *port = *pref = NULL;
|
|
return -1;
|
|
}
|
|
|
|
static struct sockaddr *
|
|
get_sockaddr(family, name, port)
|
|
int family;
|
|
char *name, *port;
|
|
{
|
|
struct addrinfo hint, *ai;
|
|
int error;
|
|
|
|
memset(&hint, 0, sizeof(hint));
|
|
hint.ai_family = PF_UNSPEC;
|
|
hint.ai_socktype = SOCK_STREAM;
|
|
|
|
error = getaddrinfo(name, port, &hint, &ai);
|
|
if (error != 0) {
|
|
printf("%s: %s/%s\n", gai_strerror(error), name, port);
|
|
return NULL;
|
|
}
|
|
|
|
return ai->ai_addr;
|
|
}
|
|
|
|
static int
|
|
get_ulproto(str)
|
|
char *str;
|
|
{
|
|
struct ulproto_tag *cp;
|
|
|
|
/* checking the string of upper layer protocol. */
|
|
for (cp = &ulprototab[0]; cp->str; cp++) {
|
|
if (strcmp(str, cp->str) == 0)
|
|
return cp->ul_proto;
|
|
}
|
|
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
/* %%% */
|
|
void
|
|
dump_isakmp_sa(buf, len)
|
|
char *buf;
|
|
int len;
|
|
{
|
|
struct ph1dump *pd;
|
|
struct tm *tm;
|
|
char tbuf[56];
|
|
caddr_t p = NULL;
|
|
|
|
/* isakmp status header */
|
|
/* short header;
|
|
1234567890123456789012 0000000000000000:0000000000000000 000000000000
|
|
*/
|
|
char *header1 =
|
|
"Destination Cookies Created";
|
|
|
|
/* semi long header;
|
|
1234567890123456789012 0000000000000000:0000000000000000 00 X 00 X 0000-00-00 00:00:00 000000
|
|
*/
|
|
char *header2 =
|
|
"Destination Cookies ST S V E Created Phase2";
|
|
|
|
/* long header;
|
|
0000:0000:0000:0000:0000:0000:0000:0000.00000 0000:0000:0000:0000:0000:0000:0000:0000.00000 0000000000000000:0000000000000000 00 X 00 X 0000-00-00 00:00:00 000000
|
|
*/
|
|
char *header3 =
|
|
"Source Destination Cookies ST S V E Created Phase2";
|
|
|
|
/* phase status header */
|
|
/* short format;
|
|
side stats source address destination address
|
|
xxx xxxxx 1234567890123456789012 1234567890123456789012
|
|
*/
|
|
|
|
static char *estr[] = { "", "B", "M", "U", "A", "I", };
|
|
|
|
switch (long_format) {
|
|
case 0:
|
|
printf("%s\n", header1);
|
|
break;
|
|
case 1:
|
|
printf("%s\n", header2);
|
|
break;
|
|
case 2:
|
|
default:
|
|
printf("%s\n", header3);
|
|
break;
|
|
}
|
|
|
|
if (len % sizeof(*pd))
|
|
printf("invalid length %d\n", len);
|
|
len /= sizeof(*pd);
|
|
|
|
pd = (struct ph1dump *)buf;
|
|
|
|
while (len-- > 0) {
|
|
/* source address */
|
|
if (long_format >= 2) {
|
|
GETNAMEINFO((struct sockaddr *)&pd->local, _addr1_, _addr2_);
|
|
switch (long_format) {
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
p = fixed_addr(_addr1_, _addr2_, 22);
|
|
break;
|
|
case 2:
|
|
default:
|
|
p = fixed_addr(_addr1_, _addr2_, 45);
|
|
break;
|
|
}
|
|
printf("%s ", p);
|
|
}
|
|
|
|
/* destination address */
|
|
GETNAMEINFO((struct sockaddr *)&pd->remote, _addr1_, _addr2_);
|
|
switch (long_format) {
|
|
case 0:
|
|
case 1:
|
|
p = fixed_addr(_addr1_, _addr2_, 22);
|
|
break;
|
|
case 2:
|
|
default:
|
|
p = fixed_addr(_addr1_, _addr2_, 45);
|
|
break;
|
|
}
|
|
printf("%s ", p);
|
|
|
|
printf("%s ", pindex_isakmp(&pd->index));
|
|
|
|
/* statuc, side and version */
|
|
if (long_format >= 1) {
|
|
printf("%2d %c %2x ",
|
|
pd->status,
|
|
pd->side == INITIATOR ? 'I' : 'R',
|
|
pd->version);
|
|
if (ARRAYLEN(estr) > pd->etype)
|
|
printf("%s ", estr[pd->etype]);
|
|
}
|
|
|
|
/* created date */
|
|
if (pd->created) {
|
|
tm = localtime(&pd->created);
|
|
strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %T", tm);
|
|
} else
|
|
snprintf(tbuf, sizeof(tbuf), " ");
|
|
printf("%s ", tbuf);
|
|
|
|
/* counter of phase 2 */
|
|
if (long_format >= 1)
|
|
printf("%6d ", pd->ph2cnt);
|
|
|
|
printf("\n");
|
|
|
|
pd++;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* %%% */
|
|
void
|
|
dump_internal(buf, tlen)
|
|
char *buf;
|
|
int tlen;
|
|
{
|
|
struct ph2handle *iph2;
|
|
struct sockaddr *addr;
|
|
|
|
/*
|
|
short header;
|
|
source address destination address
|
|
1234567890123456789012 1234567890123456789012
|
|
*/
|
|
char *short_h1 =
|
|
"Source Destination ";
|
|
|
|
/*
|
|
long header;
|
|
source address destination address
|
|
123456789012345678901234567890123456789012345 123456789012345678901234567890123456789012345
|
|
0000:0000:0000:0000:0000:0000:0000:0000.00000 0000:0000:0000:0000:0000:0000:0000:0000.00000 0000:0000:0000:0000:0000:0000:0000:0000.00000
|
|
*/
|
|
char *long_h1 =
|
|
"Source Destination ";
|
|
|
|
printf("%s\n", long_format ? long_h1 : short_h1);
|
|
|
|
while (tlen > 0) {
|
|
iph2 = (struct ph2handle *)buf;
|
|
addr = (struct sockaddr *)(++iph2);
|
|
|
|
GETNAMEINFO(addr, _addr1_, _addr2_);
|
|
printf("%s ", long_format ?
|
|
fixed_addr(_addr1_, _addr2_, 45)
|
|
: fixed_addr(_addr1_, _addr2_, 22));
|
|
addr++;
|
|
tlen -= addr->sa_len;
|
|
|
|
GETNAMEINFO(addr, _addr1_, _addr2_);
|
|
printf("%s ", long_format ?
|
|
fixed_addr(_addr1_, _addr2_, 45)
|
|
: fixed_addr(_addr1_, _addr2_, 22));
|
|
addr++;
|
|
tlen -= addr->sa_len;
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* %%% */
|
|
char *
|
|
pindex_isakmp(index)
|
|
isakmp_index *index;
|
|
{
|
|
static char buf[64];
|
|
u_char *p;
|
|
int i, j;
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
/* copy index */
|
|
p = (u_char *)index;
|
|
for (j = 0, i = 0; i < sizeof(isakmp_index); i++) {
|
|
snprintf((char *)&buf[j], sizeof(buf) - j, "%02x", p[i]);
|
|
j += 2;
|
|
switch (i) {
|
|
case 7:
|
|
#if 0
|
|
case 15:
|
|
#endif
|
|
buf[j++] = ':';
|
|
}
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
/* print schedule */
|
|
char *str_sched_stat[] = {
|
|
"off",
|
|
"on",
|
|
"dead",
|
|
};
|
|
|
|
char *str_sched_id[] = {
|
|
"PH1resend",
|
|
"PH1lifetime",
|
|
"PH2resend",
|
|
"PSTacquire",
|
|
"PSTlifetime",
|
|
};
|
|
|
|
void
|
|
print_schedule(buf, len)
|
|
caddr_t buf;
|
|
int len;
|
|
{
|
|
struct scheddump *sc = (struct scheddump *)buf;
|
|
struct tm *tm;
|
|
char tbuf[56];
|
|
|
|
if (len % sizeof(*sc))
|
|
printf("invalid length %d\n", len);
|
|
len /= sizeof(*sc);
|
|
|
|
/* 00000000 00000000 00000000 xxx........*/
|
|
printf("index tick xtime created\n");
|
|
|
|
while (len-- > 0) {
|
|
tm = localtime(&sc->created);
|
|
strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %T", tm);
|
|
|
|
printf("%-8ld %-8ld %-8ld %s\n",
|
|
sc->id,
|
|
(long)sc->tick,
|
|
(long)sc->xtime,
|
|
tbuf);
|
|
sc++;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
char *
|
|
fixed_addr(addr, port, len)
|
|
char *addr, *port;
|
|
int len;
|
|
{
|
|
static char _addr_buf_[BUFSIZ];
|
|
char *p;
|
|
int plen, i;
|
|
|
|
/* initialize */
|
|
memset(_addr_buf_, ' ', sizeof(_addr_buf_));
|
|
|
|
plen = strlen(port);
|
|
if (len < plen + 1)
|
|
return NULL;
|
|
|
|
p = _addr_buf_;
|
|
for (i = 0; i < len - plen - 1 && addr[i] != '\0'; /*noting*/)
|
|
*p++ = addr[i++];
|
|
*p++ = '.';
|
|
|
|
for (i = 0; i < plen && port[i] != '\0'; /*noting*/)
|
|
*p++ = port[i++];
|
|
|
|
_addr_buf_[len] = '\0';
|
|
|
|
return _addr_buf_;
|
|
}
|