X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd%2Fsd-rtnl%2Frtnl-message.c;h=cfb2af31420a37fae42df25c4c968bb25dc171bd;hp=dac3061271c5f9f6f5f013e44f65ce345d353eb5;hb=2263bb9a92f25571f837700cfee4fb79721baf46;hpb=0a2478a918763f73de5d1b78ebb1023c31042583 diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c index dac306127..cfb2af314 100644 --- a/src/libsystemd/sd-rtnl/rtnl-message.c +++ b/src/libsystemd/sd-rtnl/rtnl-message.c @@ -114,6 +114,24 @@ int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char pr return 0; } +int sd_rtnl_message_route_set_src_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) { + struct rtmsg *rtm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL); + + rtm = NLMSG_DATA(m->hdr); + + if ((rtm->rtm_family == AF_INET && prefixlen > 32) || + (rtm->rtm_family == AF_INET6 && prefixlen > 128)) + return -ERANGE; + + rtm->rtm_src_len = prefixlen; + + return 0; +} + int sd_rtnl_message_route_set_scope(sd_rtnl_message *m, unsigned char scope) { struct rtmsg *rtm; @@ -128,6 +146,51 @@ int sd_rtnl_message_route_set_scope(sd_rtnl_message *m, unsigned char scope) { return 0; } +int sd_rtnl_message_route_get_family(sd_rtnl_message *m, int *family) { + struct rtmsg *rtm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL); + assert_return(family, -EINVAL); + + rtm = NLMSG_DATA(m->hdr); + + *family = rtm->rtm_family; + + return 0; +} + +int sd_rtnl_message_route_get_dst_prefixlen(sd_rtnl_message *m, unsigned char *dst_len) { + struct rtmsg *rtm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL); + assert_return(dst_len, -EINVAL); + + rtm = NLMSG_DATA(m->hdr); + + *dst_len = rtm->rtm_dst_len; + + return 0; +} + +int sd_rtnl_message_route_get_src_prefixlen(sd_rtnl_message *m, unsigned char *src_len) { + struct rtmsg *rtm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL); + assert_return(src_len, -EINVAL); + + rtm = NLMSG_DATA(m->hdr); + + *src_len = rtm->rtm_src_len; + + return 0; +} + int sd_rtnl_message_new_route(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t nlmsg_type, int rtm_family, unsigned char rtm_protocol) { @@ -135,7 +198,8 @@ int sd_rtnl_message_new_route(sd_rtnl *rtnl, sd_rtnl_message **ret, int r; assert_return(rtnl_message_type_is_route(nlmsg_type), -EINVAL); - assert_return(rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL); + assert_return((nlmsg_type == RTM_GETROUTE && rtm_family == AF_UNSPEC) || + rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL); assert_return(ret, -EINVAL); r = message_new(rtnl, ret, nlmsg_type); @@ -156,6 +220,113 @@ int sd_rtnl_message_new_route(sd_rtnl *rtnl, sd_rtnl_message **ret, return 0; } +int sd_rtnl_message_neigh_set_flags(sd_rtnl_message *m, uint8_t flags) { + struct ndmsg *ndm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL); + + ndm = NLMSG_DATA(m->hdr); + ndm->ndm_flags |= flags; + + return 0; +} + +int sd_rtnl_message_neigh_set_state(sd_rtnl_message *m, uint16_t state) { + struct ndmsg *ndm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL); + + ndm = NLMSG_DATA(m->hdr); + ndm->ndm_state |= state; + + return 0; +} + +int sd_rtnl_message_neigh_get_flags(sd_rtnl_message *m, uint8_t *flags) { + struct ndmsg *ndm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL); + + ndm = NLMSG_DATA(m->hdr); + *flags = ndm->ndm_flags; + + return 0; +} + +int sd_rtnl_message_neigh_get_state(sd_rtnl_message *m, uint16_t *state) { + struct ndmsg *ndm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL); + + ndm = NLMSG_DATA(m->hdr); + *state = ndm->ndm_state; + + return 0; +} + +int sd_rtnl_message_neigh_get_family(sd_rtnl_message *m, int *family) { + struct ndmsg *ndm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL); + assert_return(family, -EINVAL); + + ndm = NLMSG_DATA(m->hdr); + + *family = ndm->ndm_family; + + return 0; +} + +int sd_rtnl_message_neigh_get_ifindex(sd_rtnl_message *m, int *index) { + struct ndmsg *ndm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL); + assert_return(index, -EINVAL); + + ndm = NLMSG_DATA(m->hdr); + + *index = ndm->ndm_ifindex; + + return 0; +} + +int sd_rtnl_message_new_neigh(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t nlmsg_type, int index, int ndm_family) { + struct ndmsg *ndm; + int r; + + assert_return(rtnl_message_type_is_neigh(nlmsg_type), -EINVAL); + assert_return(ndm_family == AF_INET || + ndm_family == AF_INET6 || + ndm_family == PF_BRIDGE, -EINVAL); + assert_return(ret, -EINVAL); + + r = message_new(rtnl, ret, nlmsg_type); + if (r < 0) + return r; + + if (nlmsg_type == RTM_NEWNEIGH) + (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND; + + ndm = NLMSG_DATA((*ret)->hdr); + + ndm->ndm_family = ndm_family; + ndm->ndm_ifindex = index; + + return 0; +} + int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags, unsigned change) { struct ifinfomsg *ifi; @@ -186,6 +357,20 @@ int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) { return 0; } +int sd_rtnl_message_link_set_family(sd_rtnl_message *m, unsigned family) { + struct ifinfomsg *ifi; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL); + + ifi = NLMSG_DATA(m->hdr); + + ifi->ifi_family = family; + + return 0; +} + int sd_rtnl_message_new_link(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t nlmsg_type, int index) { struct ifinfomsg *ifi; @@ -213,9 +398,10 @@ int sd_rtnl_message_new_link(sd_rtnl *rtnl, sd_rtnl_message **ret, int sd_rtnl_message_request_dump(sd_rtnl_message *m, int dump) { assert_return(m, -EINVAL); assert_return(m->hdr, -EINVAL); - assert_return(m->hdr->nlmsg_type == RTM_GETLINK || - m->hdr->nlmsg_type == RTM_GETADDR || - m->hdr->nlmsg_type == RTM_GETROUTE, + assert_return(m->hdr->nlmsg_type == RTM_GETLINK || + m->hdr->nlmsg_type == RTM_GETADDR || + m->hdr->nlmsg_type == RTM_GETROUTE || + m->hdr->nlmsg_type == RTM_GETNEIGH, -EINVAL); if (dump) @@ -568,8 +754,8 @@ int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const size = (size_t)r; if (size) { - length = strnlen(data, size); - if (length >= size) + length = strnlen(data, size+1); + if (length > size) return -EINVAL; } else length = strlen(data); @@ -725,7 +911,7 @@ int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) { if (r < 0) return r; - r = add_rtattr(m, type, NULL, size); + r = add_rtattr(m, type | NLA_F_NESTED, NULL, size); if (r < 0) return r; @@ -801,6 +987,8 @@ int sd_rtnl_message_read_string(sd_rtnl_message *m, unsigned short type, const c int r; void *attr_data; + assert_return(m, -EINVAL); + r = message_attribute_has_type(m, type, NLA_STRING); if (r < 0) return r; @@ -811,7 +999,8 @@ int sd_rtnl_message_read_string(sd_rtnl_message *m, unsigned short type, const c else if (strnlen(attr_data, r) >= (size_t) r) return -EIO; - *data = (const char *) attr_data; + if (data) + *data = (const char *) attr_data; return 0; } @@ -820,6 +1009,8 @@ int sd_rtnl_message_read_u8(sd_rtnl_message *m, unsigned short type, uint8_t *da int r; void *attr_data; + assert_return(m, -EINVAL); + r = message_attribute_has_type(m, type, NLA_U8); if (r < 0) return r; @@ -830,7 +1021,8 @@ int sd_rtnl_message_read_u8(sd_rtnl_message *m, unsigned short type, uint8_t *da else if ((size_t) r < sizeof(uint8_t)) return -EIO; - *data = *(uint8_t *) attr_data; + if (data) + *data = *(uint8_t *) attr_data; return 0; } @@ -839,6 +1031,8 @@ int sd_rtnl_message_read_u16(sd_rtnl_message *m, unsigned short type, uint16_t * int r; void *attr_data; + assert_return(m, -EINVAL); + r = message_attribute_has_type(m, type, NLA_U16); if (r < 0) return r; @@ -849,7 +1043,8 @@ int sd_rtnl_message_read_u16(sd_rtnl_message *m, unsigned short type, uint16_t * else if ((size_t) r < sizeof(uint16_t)) return -EIO; - *data = *(uint16_t *) attr_data; + if (data) + *data = *(uint16_t *) attr_data; return 0; } @@ -858,6 +1053,8 @@ int sd_rtnl_message_read_u32(sd_rtnl_message *m, unsigned short type, uint32_t * int r; void *attr_data; + assert_return(m, -EINVAL); + r = message_attribute_has_type(m, type, NLA_U32); if (r < 0) return r; @@ -868,7 +1065,8 @@ int sd_rtnl_message_read_u32(sd_rtnl_message *m, unsigned short type, uint32_t * else if ((size_t)r < sizeof(uint32_t)) return -EIO; - *data = *(uint32_t *) attr_data; + if (data) + *data = *(uint32_t *) attr_data; return 0; } @@ -877,6 +1075,8 @@ int sd_rtnl_message_read_ether_addr(sd_rtnl_message *m, unsigned short type, str int r; void *attr_data; + assert_return(m, -EINVAL); + r = message_attribute_has_type(m, type, NLA_ETHER_ADDR); if (r < 0) return r; @@ -887,7 +1087,8 @@ int sd_rtnl_message_read_ether_addr(sd_rtnl_message *m, unsigned short type, str else if ((size_t)r < sizeof(struct ether_addr)) return -EIO; - memcpy(data, attr_data, sizeof(struct ether_addr)); + if (data) + memcpy(data, attr_data, sizeof(struct ether_addr)); return 0; } @@ -896,6 +1097,8 @@ int sd_rtnl_message_read_cache_info(sd_rtnl_message *m, unsigned short type, str int r; void *attr_data; + assert_return(m, -EINVAL); + r = message_attribute_has_type(m, type, NLA_CACHE_INFO); if (r < 0) return r; @@ -906,7 +1109,8 @@ int sd_rtnl_message_read_cache_info(sd_rtnl_message *m, unsigned short type, str else if ((size_t)r < sizeof(struct ifa_cacheinfo)) return -EIO; - memcpy(info, attr_data, sizeof(struct ifa_cacheinfo)); + if (info) + memcpy(info, attr_data, sizeof(struct ifa_cacheinfo)); return 0; } @@ -915,6 +1119,8 @@ int sd_rtnl_message_read_in_addr(sd_rtnl_message *m, unsigned short type, struct int r; void *attr_data; + assert_return(m, -EINVAL); + r = message_attribute_has_type(m, type, NLA_IN_ADDR); if (r < 0) return r; @@ -925,7 +1131,8 @@ int sd_rtnl_message_read_in_addr(sd_rtnl_message *m, unsigned short type, struct else if ((size_t)r < sizeof(struct in_addr)) return -EIO; - memcpy(data, attr_data, sizeof(struct in_addr)); + if (data) + memcpy(data, attr_data, sizeof(struct in_addr)); return 0; } @@ -934,6 +1141,8 @@ int sd_rtnl_message_read_in6_addr(sd_rtnl_message *m, unsigned short type, struc int r; void *attr_data; + assert_return(m, -EINVAL); + r = message_attribute_has_type(m, type, NLA_IN_ADDR); if (r < 0) return r; @@ -944,7 +1153,8 @@ int sd_rtnl_message_read_in6_addr(sd_rtnl_message *m, unsigned short type, struc else if ((size_t)r < sizeof(struct in6_addr)) return -EIO; - memcpy(data, attr_data, sizeof(struct in6_addr)); + if (data) + memcpy(data, attr_data, sizeof(struct in6_addr)); return 0; } @@ -1038,13 +1248,20 @@ uint32_t rtnl_message_get_serial(sd_rtnl_message *m) { return m->hdr->nlmsg_seq; } +int sd_rtnl_message_is_error(sd_rtnl_message *m) { + assert_return(m, 0); + assert_return(m->hdr, 0); + + return m->hdr->nlmsg_type == NLMSG_ERROR; +} + int sd_rtnl_message_get_errno(sd_rtnl_message *m) { struct nlmsgerr *err; assert_return(m, -EINVAL); assert_return(m->hdr, -EINVAL); - if (m->hdr->nlmsg_type != NLMSG_ERROR) + if (!sd_rtnl_message_is_error(m)) return 0; err = NLMSG_DATA(m->hdr); @@ -1146,6 +1363,8 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool /* from the kernel */ if (ucred->uid == 0 && ucred->pid == 0) auth = true; + else + log_debug("rtnl: ignoring message from uid %u pid %u", ucred->uid, ucred->pid); } else if (cmsg->cmsg_level == SOL_NETLINK && cmsg->cmsg_type == NETLINK_PKTINFO && cmsg->cmsg_len == CMSG_LEN(sizeof(struct nl_pktinfo))) { @@ -1224,7 +1443,7 @@ int socket_read_message(sd_rtnl *rtnl) { } } - for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len); new_msg = NLMSG_NEXT(new_msg, len)) { + for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) { _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL; const NLType *nl_type; @@ -1239,7 +1458,8 @@ int socket_read_message(sd_rtnl *rtnl) { if (new_msg->nlmsg_type == NLMSG_DONE) { /* finished reading multi-part message */ done = true; - break; + + continue; } /* check that we support this message type */ @@ -1253,8 +1473,10 @@ int socket_read_message(sd_rtnl *rtnl) { } /* check that the size matches the message type */ - if (new_msg->nlmsg_len < NLMSG_LENGTH(nl_type->size)) + if (new_msg->nlmsg_len < NLMSG_LENGTH(nl_type->size)) { + log_debug("sd-rtnl: message larger than expected, dropping"); continue; + } r = message_new_empty(rtnl, &m); if (r < 0)