X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibsystemd%2Fsd-rtnl%2Frtnl-message.c;h=36eb9f5b395d5837367b89a8400097061bf58de0;hb=09773ef4462657bffadc568d08c962041fea9944;hp=84ebf65d8ebab93f430cf52a9fb47f454101ebf9;hpb=20dff6c4ff4f6e1b88c841e523ce9cff0e150fdf;p=elogind.git diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c index 84ebf65d8..36eb9f5b3 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; @@ -143,6 +161,36 @@ int sd_rtnl_message_route_get_family(sd_rtnl_message *m, int *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) { @@ -150,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); @@ -171,6 +220,58 @@ 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; @@ -206,7 +307,9 @@ int sd_rtnl_message_new_neigh(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t nlm int r; assert_return(rtnl_message_type_is_neigh(nlmsg_type), -EINVAL); - assert_return(ndm_family == AF_INET || ndm_family == AF_INET6, -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); @@ -651,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); @@ -1145,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); @@ -1238,8 +1348,10 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool /* no data */ if (errno == ENOBUFS) log_debug("rtnl: kernel receive buffer overrun"); + else if (errno == EAGAIN) + log_debug("rtnl: no data in socket"); - return (errno == EAGAIN) ? 0 : -errno; + return (errno == EAGAIN || errno == EINTR) ? 0 : -errno; } else if (r == 0) /* connection was closed by the kernel */ return -ECONNRESET; @@ -1251,8 +1363,10 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool struct ucred *ucred = (void *)CMSG_DATA(cmsg); /* from the kernel */ - if (ucred->uid == 0 && ucred->pid == 0) + if (ucred->pid == 0) auth = true; + else + log_debug("rtnl: ignoring message from pid %u", ucred->pid); } else if (cmsg->cmsg_level == SOL_NETLINK && cmsg->cmsg_type == NETLINK_PKTINFO && cmsg->cmsg_len == CMSG_LEN(sizeof(struct nl_pktinfo))) { @@ -1263,9 +1377,17 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool } } - if (!auth) + if (!auth) { /* not from the kernel, ignore */ + if (peek) { + /* drop the message */ + r = recvmsg(fd, &msg, 0); + if (r < 0) + return (errno == EAGAIN || errno == EINTR) ? 0 : -errno; + } + return 0; + } if (group) *_group = group; @@ -1331,7 +1453,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; @@ -1346,7 +1468,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 */