From 8ce5d4ca70884654988eb86734cb3022e0b71995 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 3 Apr 2010 08:29:16 +0200 Subject: add validation infrastructure and rework attribute parsing This patch includes the new validation infrastructure which is decoupled from the attribute parsing. It is composed of: - mnl_attr_type_invalid: that allows to check if the attribute type is valid (ie. the type is not higher than WXYZ_MAX). - mnl_attr_validate: that allows to validate that there's enough room for the attribute data. The patch includes the rework of the attribute parsers. Now, you don't have to use an array of pointer to store the result of the parsing, you can use whatever data structure instead. The prototype as it follows: typedef int (*mnl_attr_cb_t)(const struct nlattr *attr, void *data); extern int mnl_attr_parse(const struct nlmsghdr *nlh, int offset, mnl_attr_cb_t cb, void *data) There are three versions of rtnl-link-dump.c that show how attribute parsing can be done now. Probably that many examples are not good idea, I may remove some of them from the tree in the future. This patch also merges mnl_attr_parse_at_offset into mnl_attr_parse. This patch modifies MNL_ALIGN so that we can use it in static arrays (the use of mnl_align() is not allowed in compilation time to initialize an array field). I have added the mnl_attr_for_each() macro and I have changed mnl_attr_for_each_nested() to declare the length variable internally. Signed-off-by: Pablo Neira Ayuso --- examples/Makefile.am | 15 +++++- examples/genl-family-get.c | 113 +++++++++++++++++++++++++++++++++++++++++---- examples/rtnl-link-dump.c | 32 ++++++++++++- examples/rtnl-link-dump2.c | 103 +++++++++++++++++++++++++++++++++++++++++ examples/rtnl-link-dump3.c | 101 ++++++++++++++++++++++++++++++++++++++++ examples/rtnl-link-event.c | 32 ++++++++++++- examples/rtnl-route-dump.c | 55 ++++++++++++++++++++-- 7 files changed, 434 insertions(+), 17 deletions(-) create mode 100644 examples/rtnl-link-dump2.c create mode 100644 examples/rtnl-link-dump3.c (limited to 'examples') diff --git a/examples/Makefile.am b/examples/Makefile.am index 92c5342..1874971 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,12 +1,23 @@ include $(top_srcdir)/Make_global.am -check_PROGRAMS = rtnl-link-dump rtnl-link-event rtnl-link-set \ - rtnl-route-dump genl-family-get +check_PROGRAMS = rtnl-link-dump rtnl-link-dump2 rtnl-link-dump3 \ + rtnl-link-event \ + rtnl-link-set \ + rtnl-route-dump \ + genl-family-get rtnl_link_dump_SOURCES = rtnl-link-dump.c rtnl_link_dump_LDADD = ../src/libmnl.la rtnl_link_dump_LDFLAGS = -dynamic -ldl +rtnl_link_dump2_SOURCES = rtnl-link-dump2.c +rtnl_link_dump2_LDADD = ../src/libmnl.la +rtnl_link_dump2_LDFLAGS = -dynamic -ldl + +rtnl_link_dump3_SOURCES = rtnl-link-dump3.c +rtnl_link_dump3_LDADD = ../src/libmnl.la +rtnl_link_dump3_LDFLAGS = -dynamic -ldl + rtnl_link_event_SOURCES = rtnl-link-event.c rtnl_link_event_LDADD = ../src/libmnl.la rtnl_link_event_LDFLAGS = -dynamic -ldl diff --git a/examples/genl-family-get.c b/examples/genl-family-get.c index 3e741cb..00f601c 100644 --- a/examples/genl-family-get.c +++ b/examples/genl-family-get.c @@ -5,15 +5,43 @@ #include #include +static int parse_mc_grps_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = (const struct nlattr **)data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_invalid(attr, CTRL_ATTR_MCAST_GRP_MAX) < 0) { + perror("mnl_attr_type_invalid"); + return MNL_CB_ERROR; + } + + switch(type) { + case CTRL_ATTR_MCAST_GRP_ID: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case CTRL_ATTR_MCAST_GRP_NAME: + if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + static void parse_genl_mc_grps(struct nlattr *nested) { struct nlattr *pos; int len; - mnl_attr_for_each_nested(pos, nested, len) { - struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX+1]; + mnl_attr_for_each_nested(pos, nested) { + struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX+1] = {}; - mnl_attr_parse_nested(pos, tb, CTRL_ATTR_MCAST_GRP_MAX); + mnl_attr_parse_nested(pos, parse_mc_grps_cb, tb); if (tb[CTRL_ATTR_MCAST_GRP_ID]) { printf("id-0x%x ", mnl_attr_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID])); @@ -26,15 +54,41 @@ static void parse_genl_mc_grps(struct nlattr *nested) } } +static int parse_family_ops_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = (const struct nlattr **)data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_invalid(attr, CTRL_ATTR_OP_MAX) < 0) { + perror("mnl_attr_type_invalid"); + return MNL_CB_ERROR; + } + + switch(type) { + case CTRL_ATTR_OP_ID: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case CTRL_ATTR_OP_MAX: + break; + default: + return MNL_CB_OK; + } + tb[type] = attr; + return MNL_CB_OK; +} + static void parse_genl_family_ops(struct nlattr *nested) { struct nlattr *pos; int len; - mnl_attr_for_each_nested(pos, nested, len) { - struct nlattr *tb[CTRL_ATTR_OP_MAX+1]; + mnl_attr_for_each_nested(pos, nested) { + struct nlattr *tb[CTRL_ATTR_OP_MAX+1] = {}; - mnl_attr_parse_nested(pos, tb, CTRL_ATTR_OP_MAX); + mnl_attr_parse_nested(pos, parse_family_ops_cb, tb); if (tb[CTRL_ATTR_OP_ID]) { printf("id-0x%x ", mnl_attr_get_u32(tb[CTRL_ATTR_OP_ID])); @@ -46,12 +100,55 @@ static void parse_genl_family_ops(struct nlattr *nested) } } +static int data_attr_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = (const struct nlattr **)data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_invalid(attr, CTRL_ATTR_MAX) < 0) { + perror("mnl_attr_type_invalid"); + return MNL_CB_ERROR; + } + + switch(type) { + case CTRL_ATTR_FAMILY_NAME: + if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case CTRL_ATTR_FAMILY_ID: + if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case CTRL_ATTR_VERSION: + case CTRL_ATTR_HDRSIZE: + case CTRL_ATTR_MAXATTR: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case CTRL_ATTR_OPS: + case CTRL_ATTR_MCAST_GROUPS: + if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + static int data_cb(const struct nlmsghdr *nlh, void *data) { - struct nlattr *tb[CTRL_ATTR_MAX+1]; + struct nlattr *tb[CTRL_ATTR_MAX+1] = {}; struct genlmsghdr *genl = mnl_nlmsg_get_data(nlh); - mnl_attr_parse_at_offset(nlh, sizeof(*genl), tb, CTRL_ATTR_MAX); + mnl_attr_parse(nlh, sizeof(*genl), data_attr_cb, tb); if (tb[CTRL_ATTR_FAMILY_NAME]) { printf("name=%s\t", mnl_attr_get_str(tb[CTRL_ATTR_FAMILY_NAME])); diff --git a/examples/rtnl-link-dump.c b/examples/rtnl-link-dump.c index 7cf061d..9e3f114 100644 --- a/examples/rtnl-link-dump.c +++ b/examples/rtnl-link-dump.c @@ -7,9 +7,37 @@ #include #include +static int data_attr_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = (const struct nlattr **)data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_invalid(attr, IFLA_MAX) < 0) { + perror("mnl_attr_type_invalid"); + return MNL_CB_ERROR; + } + + switch(type) { + case IFLA_MTU: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case IFLA_IFNAME: + if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) { + perror("mnl_attr_validate2"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + static int data_cb(const struct nlmsghdr *nlh, void *data) { - struct nlattr *tb[IFLA_MAX+1]; + struct nlattr *tb[IFLA_MAX+1] = {}; struct ifinfomsg *ifm = mnl_nlmsg_get_data(nlh); int len = mnl_nlmsg_get_len(nlh); struct nlattr *attr; @@ -23,7 +51,7 @@ static int data_cb(const struct nlmsghdr *nlh, void *data) else printf("[NOT RUNNING] "); - mnl_attr_parse_at_offset(nlh, sizeof(*ifm), tb, IFLA_MAX); + mnl_attr_parse(nlh, sizeof(*ifm), data_attr_cb, tb); if (tb[IFLA_MTU]) { printf("mtu=%d ", mnl_attr_get_u32(tb[IFLA_MTU])); } diff --git a/examples/rtnl-link-dump2.c b/examples/rtnl-link-dump2.c new file mode 100644 index 0000000..dc44c54 --- /dev/null +++ b/examples/rtnl-link-dump2.c @@ -0,0 +1,103 @@ +#include +#include +#include + +#include +#include +#include +#include + +static int data_attr_cb(const struct nlattr *attr, void *data) +{ + if (mnl_attr_type_invalid(attr, IFLA_MAX) < 0) { + perror("mnl_attr_type_invalid"); + return MNL_CB_ERROR; + } + + switch(mnl_attr_get_type(attr)) { + case IFLA_MTU: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + printf("mtu=%d ", mnl_attr_get_u32(attr)); + break; + case IFLA_IFNAME: + if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) { + perror("mnl_attr_validate2"); + return MNL_CB_ERROR; + } + printf("name=%s ", mnl_attr_get_str(attr)); + break; + } + return MNL_CB_OK; +} + +static int data_cb(const struct nlmsghdr *nlh, void *data) +{ + struct ifinfomsg *ifm = mnl_nlmsg_get_data(nlh); + int len = mnl_nlmsg_get_len(nlh); + struct nlattr *attr; + + printf("index=%d type=%d flags=%d family=%d ", + ifm->ifi_index, ifm->ifi_type, + ifm->ifi_flags, ifm->ifi_family); + + if (ifm->ifi_flags & IFF_RUNNING) + printf("[RUNNING] "); + else + printf("[NOT RUNNING] "); + + mnl_attr_parse(nlh, sizeof(*ifm), data_attr_cb, NULL); + printf("\n"); + return MNL_CB_OK; +} + +int main() +{ + struct mnl_socket *nl; + char buf[getpagesize()]; + struct nlmsghdr *nlh; + struct rtgenmsg *rt; + int ret; + unsigned int seq; + + nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = RTM_GETLINK; + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + nlh->nlmsg_seq = seq = time(NULL); + rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg)); + rt->rtgen_family = AF_PACKET; + + nl = mnl_socket_open(NETLINK_ROUTE); + if (nl == NULL) { + perror("mnl_socket_open"); + exit(EXIT_FAILURE); + } + + if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { + perror("mnl_socket_bind"); + exit(EXIT_FAILURE); + } + + if (mnl_socket_sendto(nl, nlh, mnl_nlmsg_get_len(nlh)) < 0) { + perror("mnl_socket_send"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + while (ret > 0) { + ret = mnl_cb_run(buf, ret, seq, data_cb, NULL); + if (ret <= MNL_CB_STOP) + break; + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + } + if (ret == -1) { + perror("error"); + exit(EXIT_FAILURE); + } + + mnl_socket_close(nl); + + return 0; +} diff --git a/examples/rtnl-link-dump3.c b/examples/rtnl-link-dump3.c new file mode 100644 index 0000000..d5e4458 --- /dev/null +++ b/examples/rtnl-link-dump3.c @@ -0,0 +1,101 @@ +#include +#include +#include + +#include +#include +#include +#include + +static int data_cb(const struct nlmsghdr *nlh, void *data) +{ + struct ifinfomsg *ifm = mnl_nlmsg_get_data(nlh); + int len = mnl_nlmsg_get_len(nlh); + struct nlattr *attr; + + printf("index=%d type=%d flags=%d family=%d ", + ifm->ifi_index, ifm->ifi_type, + ifm->ifi_flags, ifm->ifi_family); + + if (ifm->ifi_flags & IFF_RUNNING) + printf("[RUNNING] "); + else + printf("[NOT RUNNING] "); + + mnl_attr_for_each(attr, nlh, sizeof(*ifm)) { + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_invalid(attr, IFLA_MAX) < 0) { + perror("mnl_attr_type_invalid"); + return MNL_CB_ERROR; + } + switch(type) { + case IFLA_MTU: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + printf("mtu=%d ", mnl_attr_get_u32(attr)); + break; + case IFLA_IFNAME: + if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + printf("name=%s ", mnl_attr_get_str(attr)); + break; + } + } + printf("\n"); + + return MNL_CB_OK; +} + +int main() +{ + struct mnl_socket *nl; + char buf[getpagesize()]; + struct nlmsghdr *nlh; + struct rtgenmsg *rt; + int ret; + unsigned int seq; + + nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = RTM_GETLINK; + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + nlh->nlmsg_seq = seq = time(NULL); + rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg)); + rt->rtgen_family = AF_PACKET; + + nl = mnl_socket_open(NETLINK_ROUTE); + if (nl == NULL) { + perror("mnl_socket_open"); + exit(EXIT_FAILURE); + } + + if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { + perror("mnl_socket_bind"); + exit(EXIT_FAILURE); + } + + if (mnl_socket_sendto(nl, nlh, mnl_nlmsg_get_len(nlh)) < 0) { + perror("mnl_socket_send"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + while (ret > 0) { + ret = mnl_cb_run(buf, ret, seq, data_cb, NULL); + if (ret <= MNL_CB_STOP) + break; + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + } + if (ret == -1) { + perror("error"); + exit(EXIT_FAILURE); + } + + mnl_socket_close(nl); + + return 0; +} diff --git a/examples/rtnl-link-event.c b/examples/rtnl-link-event.c index ed5a577..3e25b6f 100644 --- a/examples/rtnl-link-event.c +++ b/examples/rtnl-link-event.c @@ -7,9 +7,37 @@ #include #include +static int data_attr_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = (const struct nlattr **)data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_invalid(attr, IFLA_MAX) < 0) { + perror("mnl_attr_type_invalid"); + return MNL_CB_ERROR; + } + + switch(type) { + case IFLA_MTU: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case IFLA_IFNAME: + if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) { + perror("mnl_attr_validate2"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + static int data_cb(const struct nlmsghdr *nlh, void *data) { - struct nlattr *tb[IFLA_MAX+1]; + struct nlattr *tb[IFLA_MAX+1] = {}; struct ifinfomsg *ifm = mnl_nlmsg_get_data(nlh); int len = mnl_nlmsg_get_len(nlh); struct nlattr *attr; @@ -23,7 +51,7 @@ static int data_cb(const struct nlmsghdr *nlh, void *data) else printf("[NOT RUNNING] "); - mnl_attr_parse_at_offset(nlh, sizeof(*ifm), tb, IFLA_MAX); + mnl_attr_parse(nlh, sizeof(*ifm), data_attr_cb, tb); if (tb[IFLA_MTU]) { printf("mtu=%d ", mnl_attr_get_u32(tb[IFLA_MTU])); } diff --git a/examples/rtnl-route-dump.c b/examples/rtnl-route-dump.c index e8f3a0c..eb36bbc 100644 --- a/examples/rtnl-route-dump.c +++ b/examples/rtnl-route-dump.c @@ -7,6 +7,22 @@ #include #include +static int data_attr_cb2(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = (const struct nlattr **)data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_invalid(attr, RTAX_MAX) < 0) { + perror("mnl_attr_type_invalid"); + return MNL_CB_ERROR; + } + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + return MNL_CB_OK; +} + static void attributes_show_ipv4(struct nlattr *tb[]) { if (tb[RTA_TABLE]) { @@ -35,7 +51,7 @@ static void attributes_show_ipv4(struct nlattr *tb[]) int i; struct nlattr *tbx[RTAX_MAX+1] = {}; - mnl_attr_parse_nested(tb[RTA_METRICS], tbx, RTAX_MAX); + mnl_attr_parse_nested(tb[RTA_METRICS], data_attr_cb2, tbx); for (i=0; irtm_flags); - mnl_attr_parse_at_offset(nlh, sizeof(*rm), tb, RTA_MAX); + mnl_attr_parse(nlh, sizeof(*rm), data_attr_cb, tb); switch(rm->rtm_family) { case AF_INET: -- cgit v1.2.3