Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  setsockopt-closed.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/* Author: Dmitry Safonov <dima@arista.com> */
#include <inttypes.h>
#include "../../../../include/linux/kernel.h"
#include "aolib.h"

static union tcp_addr tcp_md5_client;

#define FILTER_TEST_NKEYS 16

static int test_port = 7788;
static void make_listen(int sk)
{
 sockaddr_af addr;

 tcp_addr_to_sockaddr_in(&addr, &this_ip_addr, htons(test_port++));
 if (bind(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0)
  test_error("bind()");
 if (listen(sk, 1))
  test_error("listen()");
}

static void test_vefify_ao_info(int sk, struct tcp_ao_info_opt *info,
    const char *tst)
{
 struct tcp_ao_info_opt tmp = {};
 socklen_t len = sizeof(tmp);

 if (getsockopt(sk, IPPROTO_TCP, TCP_AO_INFO, &tmp, &len))
  test_error("getsockopt(TCP_AO_INFO) failed");

#define __cmp_ao(member)       \
do {          \
 if (info->member != tmp.member) {     \
  test_fail("%s: getsockopt(): " __stringify(member) " %" PRIu64 " != %" PRIu64, \
     tst, (uint64_t)info->member, (uint64_t)tmp.member); \
  return;        \
 }         \
while(0)
 if (info->set_current)
  __cmp_ao(current_key);
 if (info->set_rnext)
  __cmp_ao(rnext);
 if (info->set_counters) {
  __cmp_ao(pkt_good);
  __cmp_ao(pkt_bad);
  __cmp_ao(pkt_key_not_found);
  __cmp_ao(pkt_ao_required);
  __cmp_ao(pkt_dropped_icmp);
 }
 __cmp_ao(ao_required);
 __cmp_ao(accept_icmps);

 test_ok("AO info get: %s", tst);
#undef __cmp_ao
}

static void __setsockopt_checked(int sk, int optname, bool get,
     void *optval, socklen_t *len,
     int err, const char *tst, const char *tst2)
{
 int ret;

 if (!tst)
  tst = "";
 if (!tst2)
  tst2 = "";

 errno = 0;
 if (get)
  ret = getsockopt(sk, IPPROTO_TCP, optname, optval, len);
 else
  ret = setsockopt(sk, IPPROTO_TCP, optname, optval, *len);
 if (ret == -1) {
  if (errno == err)
   test_ok("%s%s", tst ?: "", tst2 ?: "");
  else
   test_fail("%s%s: %setsockopt() failed",
      tst, tst2, get ? "g" : "s");
  close(sk);
  return;
 }

 if (err) {
  test_fail("%s%s: %setsockopt() was expected to fail with %d",
     tst, tst2, get ? "g" : "s", err);
 } else {
  test_ok("%s%s", tst ?: "", tst2 ?: "");
  if (optname == TCP_AO_ADD_KEY) {
   test_verify_socket_key(sk, optval);
  } else if (optname == TCP_AO_INFO && !get) {
   test_vefify_ao_info(sk, optval, tst2);
  } else if (optname == TCP_AO_GET_KEYS) {
   if (*len != sizeof(struct tcp_ao_getsockopt))
    test_fail("%s%s: get keys returned wrong tcp_ao_getsockopt size",
       tst, tst2);
  }
 }
 close(sk);
}

static void setsockopt_checked(int sk, int optname, void *optval,
          int err, const char *tst)
{
 const char *cmd = NULL;
 socklen_t len;

 switch (optname) {
 case TCP_AO_ADD_KEY:
  cmd = "key add: ";
  len = sizeof(struct tcp_ao_add);
  break;
 case TCP_AO_DEL_KEY:
  cmd = "key del: ";
  len = sizeof(struct tcp_ao_del);
  break;
 case TCP_AO_INFO:
  cmd = "AO info set: ";
  len = sizeof(struct tcp_ao_info_opt);
  break;
 default:
  break;
 }

 __setsockopt_checked(sk, optname, false, optval, &len, err, cmd, tst);
}

static int prepare_defs(int cmd, void *optval)
{
 int sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);

 if (sk < 0)
  test_error("socket()");

 switch (cmd) {
 case TCP_AO_ADD_KEY: {
  struct tcp_ao_add *add = optval;

  if (test_prepare_def_key(add, DEFAULT_TEST_PASSWORD, 0, this_ip_dest,
     -1, 0, 100, 100))
   test_error("prepare default tcp_ao_add");
  break;
  }
 case TCP_AO_DEL_KEY: {
  struct tcp_ao_del *del = optval;

  if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest,
     DEFAULT_TEST_PREFIX, 100, 100))
   test_error("add default key");
  memset(del, 0, sizeof(struct tcp_ao_del));
  del->sndid = 100;
  del->rcvid = 100;
  del->prefix = DEFAULT_TEST_PREFIX;
  tcp_addr_to_sockaddr_in(&del->addr, &this_ip_dest, 0);
  break;
  }
 case TCP_AO_INFO: {
  struct tcp_ao_info_opt *info = optval;

  if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest,
     DEFAULT_TEST_PREFIX, 100, 100))
   test_error("add default key");
  memset(info, 0, sizeof(struct tcp_ao_info_opt));
  break;
  }
 case TCP_AO_GET_KEYS: {
  struct tcp_ao_getsockopt *get = optval;

  if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest,
     DEFAULT_TEST_PREFIX, 100, 100))
   test_error("add default key");
  memset(get, 0, sizeof(struct tcp_ao_getsockopt));
  get->nkeys = 1;
  get->get_all = 1;
  break;
  }
 default:
  test_error("unknown cmd");
 }

 return sk;
}

static void test_extend(int cmd, bool get, const char *tst, socklen_t under_size)
{
 struct {
  union {
   struct tcp_ao_add add;
   struct tcp_ao_del del;
   struct tcp_ao_getsockopt get;
   struct tcp_ao_info_opt info;
  };
  char *extend[100];
 } tmp_opt;
 socklen_t extended_size = sizeof(tmp_opt);
 int sk;

 memset(&tmp_opt, 0, sizeof(tmp_opt));
 sk = prepare_defs(cmd, &tmp_opt);
 __setsockopt_checked(sk, cmd, get, &tmp_opt, &under_size,
        EINVAL, tst, ": minimum size");

 memset(&tmp_opt, 0, sizeof(tmp_opt));
 sk = prepare_defs(cmd, &tmp_opt);
 __setsockopt_checked(sk, cmd, get, &tmp_opt, &extended_size,
        0, tst, ": extended size");

 memset(&tmp_opt, 0, sizeof(tmp_opt));
 sk = prepare_defs(cmd, &tmp_opt);
 __setsockopt_checked(sk, cmd, get, NULL, &extended_size,
        EFAULT, tst, ": null optval");

 if (get) {
  memset(&tmp_opt, 0, sizeof(tmp_opt));
  sk = prepare_defs(cmd, &tmp_opt);
  __setsockopt_checked(sk, cmd, get, &tmp_opt, NULL,
         EFAULT, tst, ": null optlen");
 }
}

static void extend_tests(void)
{
 test_extend(TCP_AO_ADD_KEY, false"AO add",
      offsetof(struct tcp_ao_add, key));
 test_extend(TCP_AO_DEL_KEY, false"AO del",
      offsetof(struct tcp_ao_del, keyflags));
 test_extend(TCP_AO_INFO, false"AO set info",
      offsetof(struct tcp_ao_info_opt, pkt_dropped_icmp));
 test_extend(TCP_AO_INFO, true"AO get info", -1);
 test_extend(TCP_AO_GET_KEYS, true"AO get keys", -1);
}

static void test_optmem_limit(void)
{
 size_t i, keys_limit, current_optmem = test_get_optmem();
 struct tcp_ao_add ao;
 union tcp_addr net = {};
 int sk;

 if (inet_pton(TEST_FAMILY, TEST_NETWORK, &net) != 1)
  test_error("Can't convert ip address %s", TEST_NETWORK);

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 keys_limit = current_optmem / KERNEL_TCP_AO_KEY_SZ_ROUND_UP;
 for (i = 0;; i++) {
  union tcp_addr key_peer;
  int err;

  key_peer = gen_tcp_addr(net, i + 1);
  tcp_addr_to_sockaddr_in(&ao.addr, &key_peer, 0);
  err = setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY,
     &ao, sizeof(ao));
  if (!err) {
   /*
 * TCP_AO_ADD_KEY should be the same order as the real
 * sizeof(struct tcp_ao_key) in kernel.
 */

   if (i <= keys_limit * 10)
    continue;
   test_fail("optmem limit test failed: added %zu key", i);
   break;
  }
  if (i < keys_limit) {
   test_fail("optmem limit test failed: couldn't add %zu key", i);
   break;
  }
  test_ok("optmem limit was hit on adding %zu key", i);
  break;
 }
 close(sk);
}

static void test_einval_add_key(void)
{
 struct tcp_ao_add ao;
 int sk;

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 ao.keylen = TCP_AO_MAXKEYLEN + 1;
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "too big keylen");

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 ao.reserved = 1;
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "using reserved padding");

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 ao.reserved2 = 1;
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "using reserved2 padding");

 /* tcp_ao_verify_ipv{4,6}() checks */
 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 ao.addr.ss_family = AF_UNIX;
 memcpy(&ao.addr, &SOCKADDR_ANY, sizeof(SOCKADDR_ANY));
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "wrong address family");

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 tcp_addr_to_sockaddr_in(&ao.addr, &this_ip_dest, 1234);
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "port (unsupported)");

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 ao.prefix = 0;
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "no prefix, addr");

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 ao.prefix = 0;
 memcpy(&ao.addr, &SOCKADDR_ANY, sizeof(SOCKADDR_ANY));
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, 0, "no prefix, any addr");

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 ao.prefix = 32;
 memcpy(&ao.addr, &SOCKADDR_ANY, sizeof(SOCKADDR_ANY));
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "prefix, any addr");

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 ao.prefix = 129;
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "too big prefix");

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 ao.prefix = 2;
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "too short prefix");

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 ao.keyflags = (uint8_t)(-1);
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "bad key flags");

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 make_listen(sk);
 ao.set_current = 1;
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "add current key on a listen socket");

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 make_listen(sk);
 ao.set_rnext = 1;
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "add rnext key on a listen socket");

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 make_listen(sk);
 ao.set_current = 1;
 ao.set_rnext = 1;
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "add current+rnext key on a listen socket");

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 ao.set_current = 1;
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, 0, "add key and set as current");

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 ao.set_rnext = 1;
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, 0, "add key and set as rnext");

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 ao.set_current = 1;
 ao.set_rnext = 1;
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, 0, "add key and set as current+rnext");

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 ao.ifindex = 42;
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL,
      "ifindex without TCP_AO_KEYF_IFNINDEX");

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 ao.keyflags |= TCP_AO_KEYF_IFINDEX;
 ao.ifindex = 42;
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "non-existent VRF");
 /*
 * tcp_md5_do_lookup{,_any_l3index}() are checked in unsigned-md5
 * see client_vrf_tests().
 */


 test_optmem_limit();

 /* tcp_ao_parse_crypto() */
 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 ao.maclen = 100;
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EMSGSIZE, "maclen bigger than TCP hdr");

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 strcpy(ao.alg_name, "imaginary hash algo");
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, ENOENT, "bad algo");
}

static void test_einval_del_key(void)
{
 struct tcp_ao_del del;
 int sk;

 sk = prepare_defs(TCP_AO_DEL_KEY, &del);
 del.reserved = 1;
 setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, EINVAL, "using reserved padding");

 sk = prepare_defs(TCP_AO_DEL_KEY, &del);
 del.reserved2 = 1;
 setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, EINVAL, "using reserved2 padding");

 sk = prepare_defs(TCP_AO_DEL_KEY, &del);
 make_listen(sk);
 if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest, DEFAULT_TEST_PREFIX, 0, 0))
  test_error("add key");
 del.set_current = 1;
 setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, EINVAL, "del and set current key on a listen socket");

 sk = prepare_defs(TCP_AO_DEL_KEY, &del);
 make_listen(sk);
 if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest, DEFAULT_TEST_PREFIX, 0, 0))
  test_error("add key");
 del.set_rnext = 1;
 setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, EINVAL, "del and set rnext key on a listen socket");

 sk = prepare_defs(TCP_AO_DEL_KEY, &del);
 make_listen(sk);
 if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest, DEFAULT_TEST_PREFIX, 0, 0))
  test_error("add key");
 del.set_current = 1;
 del.set_rnext = 1;
 setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, EINVAL, "del and set current+rnext key on a listen socket");

 sk = prepare_defs(TCP_AO_DEL_KEY, &del);
 del.keyflags = (uint8_t)(-1);
 setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, EINVAL, "bad key flags");

 sk = prepare_defs(TCP_AO_DEL_KEY, &del);
 del.ifindex = 42;
 setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, EINVAL,
      "ifindex without TCP_AO_KEYF_IFNINDEX");

 sk = prepare_defs(TCP_AO_DEL_KEY, &del);
 del.keyflags |= TCP_AO_KEYF_IFINDEX;
 del.ifindex = 42;
 setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, ENOENT, "non-existent VRF");

 sk = prepare_defs(TCP_AO_DEL_KEY, &del);
 del.set_current = 1;
 setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, ENOENT, "set non-existing current key");

 sk = prepare_defs(TCP_AO_DEL_KEY, &del);
 del.set_rnext = 1;
 setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, ENOENT, "set non-existing rnext key");

 sk = prepare_defs(TCP_AO_DEL_KEY, &del);
 del.set_current = 1;
 del.set_rnext = 1;
 setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, ENOENT, "set non-existing current+rnext key");

 sk = prepare_defs(TCP_AO_DEL_KEY, &del);
 if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest, DEFAULT_TEST_PREFIX, 0, 0))
  test_error("add key");
 del.set_current = 1;
 setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, 0, "set current key");

 sk = prepare_defs(TCP_AO_DEL_KEY, &del);
 if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest, DEFAULT_TEST_PREFIX, 0, 0))
  test_error("add key");
 del.set_rnext = 1;
 setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, 0, "set rnext key");

 sk = prepare_defs(TCP_AO_DEL_KEY, &del);
 if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest, DEFAULT_TEST_PREFIX, 0, 0))
  test_error("add key");
 del.set_current = 1;
 del.set_rnext = 1;
 setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, 0, "set current+rnext key");

 sk = prepare_defs(TCP_AO_DEL_KEY, &del);
 del.set_current = 1;
 del.current_key = 100;
 setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, ENOENT, "set as current key to be removed");

 sk = prepare_defs(TCP_AO_DEL_KEY, &del);
 del.set_rnext = 1;
 del.rnext = 100;
 setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, ENOENT, "set as rnext key to be removed");

 sk = prepare_defs(TCP_AO_DEL_KEY, &del);
 del.set_current = 1;
 del.current_key = 100;
 del.set_rnext = 1;
 del.rnext = 100;
 setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, ENOENT, "set as current+rnext key to be removed");

 sk = prepare_defs(TCP_AO_DEL_KEY, &del);
 del.del_async = 1;
 setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, EINVAL, "async on non-listen");

 sk = prepare_defs(TCP_AO_DEL_KEY, &del);
 del.sndid = 101;
 setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, ENOENT, "non-existing sndid");

 sk = prepare_defs(TCP_AO_DEL_KEY, &del);
 del.rcvid = 101;
 setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, ENOENT, "non-existing rcvid");

 sk = prepare_defs(TCP_AO_DEL_KEY, &del);
 tcp_addr_to_sockaddr_in(&del.addr, &this_ip_addr, 0);
 setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, ENOENT, "incorrect addr");

 sk = prepare_defs(TCP_AO_DEL_KEY, &del);
 setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, 0, "correct key delete");
}

static void test_einval_ao_info(void)
{
 struct tcp_ao_info_opt info;
 int sk;

 sk = prepare_defs(TCP_AO_INFO, &info);
 make_listen(sk);
 info.set_current = 1;
 setsockopt_checked(sk, TCP_AO_INFO, &info, EINVAL, "set current key on a listen socket");

 sk = prepare_defs(TCP_AO_INFO, &info);
 make_listen(sk);
 info.set_rnext = 1;
 setsockopt_checked(sk, TCP_AO_INFO, &info, EINVAL, "set rnext key on a listen socket");

 sk = prepare_defs(TCP_AO_INFO, &info);
 make_listen(sk);
 info.set_current = 1;
 info.set_rnext = 1;
 setsockopt_checked(sk, TCP_AO_INFO, &info, EINVAL, "set current+rnext key on a listen socket");

 sk = prepare_defs(TCP_AO_INFO, &info);
 info.reserved = 1;
 setsockopt_checked(sk, TCP_AO_INFO, &info, EINVAL, "using reserved padding");

 sk = prepare_defs(TCP_AO_INFO, &info);
 info.reserved2 = 1;
 setsockopt_checked(sk, TCP_AO_INFO, &info, EINVAL, "using reserved2 padding");

 sk = prepare_defs(TCP_AO_INFO, &info);
 info.accept_icmps = 1;
 setsockopt_checked(sk, TCP_AO_INFO, &info, 0, "accept_icmps");

 sk = prepare_defs(TCP_AO_INFO, &info);
 info.ao_required = 1;
 setsockopt_checked(sk, TCP_AO_INFO, &info, 0, "ao required");

 if (!should_skip_test("ao required with MD5 key", KCONFIG_TCP_MD5)) {
  sk = prepare_defs(TCP_AO_INFO, &info);
  info.ao_required = 1;
  if (test_set_md5(sk, tcp_md5_client, TEST_PREFIX, -1,
     "long long secret")) {
   test_error("setsockopt(TCP_MD5SIG_EXT)");
   close(sk);
  } else {
   setsockopt_checked(sk, TCP_AO_INFO, &info, EKEYREJECTED,
        "ao required with MD5 key");
  }
 }

 sk = prepare_defs(TCP_AO_INFO, &info);
 info.set_current = 1;
 setsockopt_checked(sk, TCP_AO_INFO, &info, ENOENT, "set non-existing current key");

 sk = prepare_defs(TCP_AO_INFO, &info);
 info.set_rnext = 1;
 setsockopt_checked(sk, TCP_AO_INFO, &info, ENOENT, "set non-existing rnext key");

 sk = prepare_defs(TCP_AO_INFO, &info);
 info.set_current = 1;
 info.set_rnext = 1;
 setsockopt_checked(sk, TCP_AO_INFO, &info, ENOENT, "set non-existing current+rnext key");

 sk = prepare_defs(TCP_AO_INFO, &info);
 info.set_current = 1;
 info.current_key = 100;
 setsockopt_checked(sk, TCP_AO_INFO, &info, 0, "set current key");

 sk = prepare_defs(TCP_AO_INFO, &info);
 info.set_rnext = 1;
 info.rnext = 100;
 setsockopt_checked(sk, TCP_AO_INFO, &info, 0, "set rnext key");

 sk = prepare_defs(TCP_AO_INFO, &info);
 info.set_current = 1;
 info.set_rnext = 1;
 info.current_key = 100;
 info.rnext = 100;
 setsockopt_checked(sk, TCP_AO_INFO, &info, 0, "set current+rnext key");

 sk = prepare_defs(TCP_AO_INFO, &info);
 info.set_counters = 1;
 info.pkt_good = 321;
 info.pkt_bad = 888;
 info.pkt_key_not_found = 654;
 info.pkt_ao_required = 987654;
 info.pkt_dropped_icmp = 10000;
 setsockopt_checked(sk, TCP_AO_INFO, &info, 0, "set counters");

 sk = prepare_defs(TCP_AO_INFO, &info);
 setsockopt_checked(sk, TCP_AO_INFO, &info, 0, "no-op");
}

static void getsockopt_checked(int sk, struct tcp_ao_getsockopt *optval,
          int err, const char *tst)
{
 socklen_t len = sizeof(struct tcp_ao_getsockopt);

 __setsockopt_checked(sk, TCP_AO_GET_KEYS, true, optval, &len, err,
        "get keys: ", tst);
}

static void test_einval_get_keys(void)
{
 struct tcp_ao_getsockopt out;
 int sk;

 sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
 if (sk < 0)
  test_error("socket()");
 getsockopt_checked(sk, &out, ENOENT, "no ao_info");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 getsockopt_checked(sk, &out, 0, "proper tcp_ao_get_mkts()");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.pkt_good = 643;
 getsockopt_checked(sk, &out, EINVAL, "set out-only pkt_good counter");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.pkt_bad = 94;
 getsockopt_checked(sk, &out, EINVAL, "set out-only pkt_bad counter");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.keyflags = (uint8_t)(-1);
 getsockopt_checked(sk, &out, EINVAL, "bad keyflags");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.ifindex = 42;
 getsockopt_checked(sk, &out, EINVAL,
      "ifindex without TCP_AO_KEYF_IFNINDEX");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.reserved = 1;
 getsockopt_checked(sk, &out, EINVAL, "using reserved field");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.get_all = 0;
 out.prefix = 0;
 tcp_addr_to_sockaddr_in(&out.addr, &this_ip_dest, 0);
 getsockopt_checked(sk, &out, EINVAL, "no prefix, addr");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.get_all = 0;
 out.prefix = 0;
 memcpy(&out.addr, &SOCKADDR_ANY, sizeof(SOCKADDR_ANY));
 getsockopt_checked(sk, &out, 0, "no prefix, any addr");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.get_all = 0;
 out.prefix = 32;
 memcpy(&out.addr, &SOCKADDR_ANY, sizeof(SOCKADDR_ANY));
 getsockopt_checked(sk, &out, EINVAL, "prefix, any addr");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.get_all = 0;
 out.prefix = 129;
 tcp_addr_to_sockaddr_in(&out.addr, &this_ip_dest, 0);
 getsockopt_checked(sk, &out, EINVAL, "too big prefix");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.get_all = 0;
 out.prefix = 2;
 tcp_addr_to_sockaddr_in(&out.addr, &this_ip_dest, 0);
 getsockopt_checked(sk, &out, EINVAL, "too short prefix");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.get_all = 0;
 out.prefix = DEFAULT_TEST_PREFIX;
 tcp_addr_to_sockaddr_in(&out.addr, &this_ip_dest, 0);
 getsockopt_checked(sk, &out, 0, "prefix + addr");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.get_all = 1;
 out.prefix = DEFAULT_TEST_PREFIX;
 getsockopt_checked(sk, &out, EINVAL, "get_all + prefix");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.get_all = 1;
 tcp_addr_to_sockaddr_in(&out.addr, &this_ip_dest, 0);
 getsockopt_checked(sk, &out, EINVAL, "get_all + addr");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.get_all = 1;
 out.sndid = 1;
 getsockopt_checked(sk, &out, EINVAL, "get_all + sndid");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.get_all = 1;
 out.rcvid = 1;
 getsockopt_checked(sk, &out, EINVAL, "get_all + rcvid");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.get_all = 0;
 out.is_current = 1;
 out.prefix = DEFAULT_TEST_PREFIX;
 getsockopt_checked(sk, &out, EINVAL, "current + prefix");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.get_all = 0;
 out.is_current = 1;
 tcp_addr_to_sockaddr_in(&out.addr, &this_ip_dest, 0);
 getsockopt_checked(sk, &out, EINVAL, "current + addr");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.get_all = 0;
 out.is_current = 1;
 out.sndid = 1;
 getsockopt_checked(sk, &out, EINVAL, "current + sndid");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.get_all = 0;
 out.is_current = 1;
 out.rcvid = 1;
 getsockopt_checked(sk, &out, EINVAL, "current + rcvid");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.get_all = 0;
 out.is_rnext = 1;
 out.prefix = DEFAULT_TEST_PREFIX;
 getsockopt_checked(sk, &out, EINVAL, "rnext + prefix");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.get_all = 0;
 out.is_rnext = 1;
 tcp_addr_to_sockaddr_in(&out.addr, &this_ip_dest, 0);
 getsockopt_checked(sk, &out, EINVAL, "rnext + addr");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.get_all = 0;
 out.is_rnext = 1;
 out.sndid = 1;
 getsockopt_checked(sk, &out, EINVAL, "rnext + sndid");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.get_all = 0;
 out.is_rnext = 1;
 out.rcvid = 1;
 getsockopt_checked(sk, &out, EINVAL, "rnext + rcvid");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.get_all = 1;
 out.is_current = 1;
 getsockopt_checked(sk, &out, EINVAL, "get_all + current");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.get_all = 1;
 out.is_rnext = 1;
 getsockopt_checked(sk, &out, EINVAL, "get_all + rnext");

 sk = prepare_defs(TCP_AO_GET_KEYS, &out);
 out.get_all = 0;
 out.is_current = 1;
 out.is_rnext = 1;
 getsockopt_checked(sk, &out, 0, "current + rnext");
}

static void einval_tests(void)
{
 test_einval_add_key();
 test_einval_del_key();
 test_einval_ao_info();
 test_einval_get_keys();
}

static void duplicate_tests(void)
{
 union tcp_addr network_dup;
 struct tcp_ao_add ao, ao2;
 int sk;

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 if (setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &ao, sizeof(ao)))
  test_error("setsockopt()");
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EEXIST, "duplicate: full copy");

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 ao2 = ao;
 memcpy(&ao2.addr, &SOCKADDR_ANY, sizeof(SOCKADDR_ANY));
 ao2.prefix = 0;
 if (setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &ao2, sizeof(ao)))
  test_error("setsockopt()");
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EEXIST, "duplicate: any addr key on the socket");

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 if (setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &ao, sizeof(ao)))
  test_error("setsockopt()");
 memcpy(&ao.addr, &SOCKADDR_ANY, sizeof(SOCKADDR_ANY));
 ao.prefix = 0;
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EEXIST, "duplicate: add any addr key");

 if (inet_pton(TEST_FAMILY, TEST_NETWORK, &network_dup) != 1)
  test_error("Can't convert ip address %s", TEST_NETWORK);
 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 if (setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &ao, sizeof(ao)))
  test_error("setsockopt()");
 if (test_prepare_def_key(&ao, "password", 0, network_dup,
     16, 0, 100, 100))
  test_error("prepare default tcp_ao_add");
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EEXIST, "duplicate: add any addr for the same subnet");

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 if (setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &ao, sizeof(ao)))
  test_error("setsockopt()");
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EEXIST, "duplicate: full copy of a key");

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 if (setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &ao, sizeof(ao)))
  test_error("setsockopt()");
 ao.rcvid = 101;
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EEXIST, "duplicate: RecvID differs");

 sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
 if (setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &ao, sizeof(ao)))
  test_error("setsockopt()");
 ao.sndid = 101;
 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EEXIST, "duplicate: SendID differs");
}

static void fetch_all_keys(int sk, struct tcp_ao_getsockopt *keys)
{
 socklen_t optlen = sizeof(struct tcp_ao_getsockopt);

 memset(keys, 0, sizeof(struct tcp_ao_getsockopt) * FILTER_TEST_NKEYS);
 keys[0].get_all = 1;
 keys[0].nkeys = FILTER_TEST_NKEYS;
 if (getsockopt(sk, IPPROTO_TCP, TCP_AO_GET_KEYS, &keys[0], &optlen))
  test_error("getsockopt");
}

static int prepare_test_keys(struct tcp_ao_getsockopt *keys)
{
 const char *test_password = "Test password number ";
 struct tcp_ao_add test_ao[FILTER_TEST_NKEYS];
 char test_password_scratch[64] = {};
 u8 rcvid = 100, sndid = 100;
 int sk;

 sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
 if (sk < 0)
  test_error("socket()");

 for (int i = 0; i < FILTER_TEST_NKEYS; i++) {
  snprintf(test_password_scratch, 64, "%s %d", test_password, i);
  test_prepare_key(&test_ao[i], DEFAULT_TEST_ALGO, this_ip_dest,
     falsefalse, DEFAULT_TEST_PREFIX, 0, sndid++,
     rcvid++, 0, 0, strlen(test_password_scratch),
     test_password_scratch);
 }
 test_ao[0].set_current = 1;
 test_ao[1].set_rnext = 1;
 /* One key with a different addr and overlapping sndid, rcvid */
 tcp_addr_to_sockaddr_in(&test_ao[2].addr, &this_ip_addr, 0);
 test_ao[2].sndid = 100;
 test_ao[2].rcvid = 100;

 /* Add keys in a random order */
 for (int i = 0; i < FILTER_TEST_NKEYS; i++) {
  int randidx = rand() % (FILTER_TEST_NKEYS - i);

  if (setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY,
          &test_ao[randidx], sizeof(struct tcp_ao_add)))
   test_error("setsockopt()");
  memcpy(&test_ao[randidx], &test_ao[FILTER_TEST_NKEYS - 1 - i],
         sizeof(struct tcp_ao_add));
 }

 fetch_all_keys(sk, keys);

 return sk;
}

/* Assumes passwords are unique */
static int compare_mkts(struct tcp_ao_getsockopt *expected, int nexpected,
   struct tcp_ao_getsockopt *actual, int nactual)
{
 int matches = 0;

 for (int i = 0; i < nexpected; i++) {
  for (int j = 0; j < nactual; j++) {
   if (memcmp(expected[i].key, actual[j].key,
       TCP_AO_MAXKEYLEN) == 0)
    matches++;
  }
 }
 return nexpected - matches;
}

static void filter_keys_checked(int sk, struct tcp_ao_getsockopt *filter,
    struct tcp_ao_getsockopt *expected,
    unsigned int nexpected, const char *tst)
{
 struct tcp_ao_getsockopt filtered_keys[FILTER_TEST_NKEYS] = {};
 struct tcp_ao_getsockopt all_keys[FILTER_TEST_NKEYS] = {};
 socklen_t len = sizeof(struct tcp_ao_getsockopt);

 fetch_all_keys(sk, all_keys);
 memcpy(&filtered_keys[0], filter, sizeof(struct tcp_ao_getsockopt));
 filtered_keys[0].nkeys = FILTER_TEST_NKEYS;
 if (getsockopt(sk, IPPROTO_TCP, TCP_AO_GET_KEYS, filtered_keys, &len))
  test_error("getsockopt");
 if (filtered_keys[0].nkeys != nexpected) {
  test_fail("wrong nr of keys, expected %u got %u", nexpected,
     filtered_keys[0].nkeys);
  goto out_close;
 }
 if (compare_mkts(expected, nexpected, filtered_keys,
    filtered_keys[0].nkeys)) {
  test_fail("got wrong keys back");
  goto out_close;
 }
 test_ok("filter keys: %s", tst);

out_close:
 close(sk);
 memset(filter, 0, sizeof(struct tcp_ao_getsockopt));
}

static void filter_tests(void)
{
 struct tcp_ao_getsockopt original_keys[FILTER_TEST_NKEYS];
 struct tcp_ao_getsockopt expected_keys[FILTER_TEST_NKEYS];
 struct tcp_ao_getsockopt filter = {};
 int sk, f, nmatches;
 socklen_t len;

 f = 2;
 sk = prepare_test_keys(original_keys);
 filter.rcvid = original_keys[f].rcvid;
 filter.sndid = original_keys[f].sndid;
 memcpy(&filter.addr, &original_keys[f].addr,
        sizeof(original_keys[f].addr));
 filter.prefix = original_keys[f].prefix;
 filter_keys_checked(sk, &filter, &original_keys[f], 1,
       "by sndid, rcvid, address");

 f = -1;
 sk = prepare_test_keys(original_keys);
 for (int i = 0; i < original_keys[0].nkeys; i++) {
  if (original_keys[i].is_current) {
   f = i;
   break;
  }
 }
 if (f < 0)
  test_error("No current key after adding one");
 filter.is_current = 1;
 filter_keys_checked(sk, &filter, &original_keys[f], 1, "by is_current");

 f = -1;
 sk = prepare_test_keys(original_keys);
 for (int i = 0; i < original_keys[0].nkeys; i++) {
  if (original_keys[i].is_rnext) {
   f = i;
   break;
  }
 }
 if (f < 0)
  test_error("No rnext key after adding one");
 filter.is_rnext = 1;
 filter_keys_checked(sk, &filter, &original_keys[f], 1, "by is_rnext");

 f = -1;
 nmatches = 0;
 sk = prepare_test_keys(original_keys);
 for (int i = 0; i < original_keys[0].nkeys; i++) {
  if (original_keys[i].sndid == 100) {
   f = i;
   memcpy(&expected_keys[nmatches], &original_keys[i],
          sizeof(struct tcp_ao_getsockopt));
   nmatches++;
  }
 }
 if (f < 0)
  test_error("No key for sndid 100");
 if (nmatches != 2)
  test_error("Should have 2 keys with sndid 100");
 filter.rcvid = original_keys[f].rcvid;
 filter.sndid = original_keys[f].sndid;
 filter.addr.ss_family = test_family;
 filter_keys_checked(sk, &filter, expected_keys, nmatches,
       "by sndid, rcvid");

 sk = prepare_test_keys(original_keys);
 filter.get_all = 1;
 filter.nkeys = FILTER_TEST_NKEYS / 2;
 len = sizeof(struct tcp_ao_getsockopt);
 if (getsockopt(sk, IPPROTO_TCP, TCP_AO_GET_KEYS, &filter, &len))
  test_error("getsockopt");
 if (filter.nkeys == FILTER_TEST_NKEYS)
  test_ok("filter keys: correct nkeys when in.nkeys < matches");
 else
  test_fail("filter keys: wrong nkeys, expected %u got %u",
     FILTER_TEST_NKEYS, filter.nkeys);
}

static void *client_fn(void *arg)
{
 if (inet_pton(TEST_FAMILY, __TEST_CLIENT_IP(2), &tcp_md5_client) != 1)
  test_error("Can't convert ip address");
 extend_tests();
 einval_tests();
 filter_tests();
 duplicate_tests();

 return NULL;
}

int main(int argc, char *argv[])
{
 test_init(126, client_fn, NULL);
 return 0;
}

Messung V0.5
C=92 H=92 G=91

¤ Dauer der Verarbeitung: 0.8 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge