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


Quelle  netlink-dumps.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0

#define _GNU_SOURCE

#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>

#include <linux/genetlink.h>
#include <linux/neighbour.h>
#include <linux/netdevice.h>
#include <linux/netlink.h>
#include <linux/mqueue.h>
#include <linux/rtnetlink.h>

#include "../kselftest_harness.h"

#include <ynl.h>

struct ext_ack {
 int err;

 __u32 attr_offs;
 __u32 miss_type;
 __u32 miss_nest;
 const char *str;
};

enum get_ea_ret {
 ERROR = -1,
 NO_CTRL = 0,
 FOUND_DONE,
 FOUND_ERR,
 FOUND_EXTACK,
};

static enum get_ea_ret
nl_get_extack(char *buf, size_t n, struct ext_ack *ea)
{
 enum get_ea_ret ret = NO_CTRL;
 const struct nlmsghdr *nlh;
 const struct nlattr *attr;
 ssize_t rem;

 for (rem = n; rem > 0; NLMSG_NEXT(nlh, rem)) {
  nlh = (struct nlmsghdr *)&buf[n - rem];
  if (!NLMSG_OK(nlh, rem))
   return ERROR;

  if (nlh->nlmsg_type == NLMSG_ERROR)
   ret = FOUND_ERR;
  else if (nlh->nlmsg_type == NLMSG_DONE)
   ret = FOUND_DONE;
  else
   continue;

  ea->err = -*(int *)NLMSG_DATA(nlh);

  if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
   return ret;

  ynl_attr_for_each(attr, nlh, sizeof(int)) {
   switch (ynl_attr_type(attr)) {
   case NLMSGERR_ATTR_OFFS:
    ea->attr_offs = ynl_attr_get_u32(attr);
    break;
   case NLMSGERR_ATTR_MISS_TYPE:
    ea->miss_type = ynl_attr_get_u32(attr);
    break;
   case NLMSGERR_ATTR_MISS_NEST:
    ea->miss_nest = ynl_attr_get_u32(attr);
    break;
   case NLMSGERR_ATTR_MSG:
    ea->str = ynl_attr_get_str(attr);
    break;
   }
  }

  return FOUND_EXTACK;
 }

 return ret;
}

static const struct {
 struct nlmsghdr nlhdr;
 struct ndmsg ndm;
 struct nlattr ahdr;
 __u32 val;
} dump_neigh_bad = {
 .nlhdr = {
  .nlmsg_len = sizeof(dump_neigh_bad),
  .nlmsg_type = RTM_GETNEIGH,
  .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP,
  .nlmsg_seq = 1,
 },
 .ndm = {
  .ndm_family = 123,
 },
 .ahdr = {
  .nla_len = 4 + 4,
  .nla_type = NDA_FLAGS_EXT,
 },
 .val = -1, // should fail MASK validation
};

TEST(dump_extack)
{
 int netlink_sock;
 int i, cnt, ret;
 char buf[8192];
 int one = 1;
 ssize_t n;

 netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
 ASSERT_GE(netlink_sock, 0);

 n = setsockopt(netlink_sock, SOL_NETLINK, NETLINK_CAP_ACK,
         &one, sizeof(one));
 ASSERT_EQ(n, 0);
 n = setsockopt(netlink_sock, SOL_NETLINK, NETLINK_EXT_ACK,
         &one, sizeof(one));
 ASSERT_EQ(n, 0);
 n = setsockopt(netlink_sock, SOL_NETLINK, NETLINK_GET_STRICT_CHK,
         &one, sizeof(one));
 ASSERT_EQ(n, 0);

 /* Dump so many times we fill up the buffer */
 cnt = 80;
 for (i = 0; i < cnt; i++) {
  n = send(netlink_sock, &dump_neigh_bad,
    sizeof(dump_neigh_bad), 0);
  ASSERT_EQ(n, sizeof(dump_neigh_bad));
 }

 /* Read out the ENOBUFS */
 n = recv(netlink_sock, buf, sizeof(buf), MSG_DONTWAIT);
 EXPECT_EQ(n, -1);
 EXPECT_EQ(errno, ENOBUFS);

 for (i = 0; i < cnt; i++) {
  struct ext_ack ea = {};

  n = recv(netlink_sock, buf, sizeof(buf), MSG_DONTWAIT);
  if (n < 0) {
   ASSERT_GE(i, 10);
   break;
  }
  ASSERT_GE(n, (ssize_t)sizeof(struct nlmsghdr));

  ret = nl_get_extack(buf, n, &ea);
  /* Once we fill the buffer we'll see one ENOBUFS followed
 * by a number of EBUSYs. Then the last recv() will finally
 * trigger and complete the dump.
 */

  if (ret == FOUND_ERR && (ea.err == ENOBUFS || ea.err == EBUSY))
   continue;
  EXPECT_EQ(ret, FOUND_EXTACK);
  EXPECT_EQ(ea.err, EINVAL);
  EXPECT_EQ(ea.attr_offs,
     sizeof(struct nlmsghdr) + sizeof(struct ndmsg));
 }
 /* Make sure last message was a full DONE+extack */
 EXPECT_EQ(ret, FOUND_EXTACK);
}

static const struct {
 struct nlmsghdr nlhdr;
 struct genlmsghdr genlhdr;
 struct nlattr ahdr;
 __u16 val;
 __u16 pad;
} dump_policies = {
 .nlhdr = {
  .nlmsg_len = sizeof(dump_policies),
  .nlmsg_type = GENL_ID_CTRL,
  .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP,
  .nlmsg_seq = 1,
 },
 .genlhdr = {
  .cmd  = CTRL_CMD_GETPOLICY,
  .version = 2,
 },
 .ahdr = {
  .nla_len = 6,
  .nla_type = CTRL_ATTR_FAMILY_ID,
 },
 .val = GENL_ID_CTRL,
 .pad = 0,
};

// Sanity check for the test itself, make sure the dump doesn't fit in one msg
TEST(test_sanity)
{
 int netlink_sock;
 char buf[8192];
 ssize_t n;

 netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
 ASSERT_GE(netlink_sock, 0);

 n = send(netlink_sock, &dump_policies, sizeof(dump_policies), 0);
 ASSERT_EQ(n, sizeof(dump_policies));

 n = recv(netlink_sock, buf, sizeof(buf), MSG_DONTWAIT);
 ASSERT_GE(n, (ssize_t)sizeof(struct nlmsghdr));

 n = recv(netlink_sock, buf, sizeof(buf), MSG_DONTWAIT);
 ASSERT_GE(n, (ssize_t)sizeof(struct nlmsghdr));

 close(netlink_sock);
}

TEST(close_in_progress)
{
 int netlink_sock;
 ssize_t n;

 netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
 ASSERT_GE(netlink_sock, 0);

 n = send(netlink_sock, &dump_policies, sizeof(dump_policies), 0);
 ASSERT_EQ(n, sizeof(dump_policies));

 close(netlink_sock);
}

TEST(close_with_ref)
{
 char cookie[NOTIFY_COOKIE_LEN] = {};
 int netlink_sock, mq_fd;
 struct sigevent sigev;
 ssize_t n;

 netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
 ASSERT_GE(netlink_sock, 0);

 n = send(netlink_sock, &dump_policies, sizeof(dump_policies), 0);
 ASSERT_EQ(n, sizeof(dump_policies));

 mq_fd = syscall(__NR_mq_open, "sed", O_CREAT | O_WRONLY, 0600, 0);
 ASSERT_GE(mq_fd, 0);

 memset(&sigev, 0, sizeof(sigev));
 sigev.sigev_notify  = SIGEV_THREAD;
 sigev.sigev_value.sival_ptr = cookie;
 sigev.sigev_signo  = netlink_sock;

 syscall(__NR_mq_notify, mq_fd, &sigev);

 close(netlink_sock);

 // give mqueue time to fire
 usleep(100 * 1000);
}

TEST_HARNESS_MAIN

Messung V0.5
C=92 H=95 G=93

¤ Dauer der Verarbeitung: 0.3 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