int find_interfaces(struct rarpd *rarpd) { if (nl_open(&rarpd->nl_ctx) != 0) { return -1; } if (get_links(rarpd) != 0) { return -1; } if (get_addresses(rarpd) != 0) { return -1; } nl_close(&rarpd->nl_ctx); return 0; }
int netlink_dad_start( int *fd ) { int status; //int fd; struct msghdr msg; struct sockaddr_nl dest_addr; struct nlmsghdr *nlh; struct iovec iov; struct dad_failed_msg_t *dad_msg; *fd = nl_open(); if ( *fd < 0) { dprintf(LOG_INFO, FNAME, "nl_open failed\n"); perror("Error\n"); return 1; } return 0; }
int nl_send(struct nl_handle *hnd, struct iovec *iov, int iovlen) { struct sockaddr_nl sa = { .nl_family = AF_NETLINK, }; struct msghdr msg = { .msg_name = &sa, .msg_namelen = sizeof(sa), .msg_iov = iov, .msg_iovlen = iovlen, }; struct nlmsghdr *src = iov->iov_base; src->nlmsg_seq = ++hnd->seq; if (sendmsg(hnd->fd, &msg, 0) < 0) return errno; return 0; } int nl_recv(struct nl_handle *hnd, struct nlmsg_entry **dest, int is_dump) { struct sockaddr_nl sa = { .nl_family = AF_NETLINK, }; struct iovec iov; struct msghdr msg = { .msg_name = &sa, .msg_namelen = sizeof(sa), .msg_iov = &iov, .msg_iovlen = 1, }; char buf[16384]; int len, err; struct nlmsghdr *n; struct nlmsg_entry *ptr = NULL; /* GCC false positive */ struct nlmsg_entry *entry; *dest = NULL; while (1) { iov.iov_base = buf; iov.iov_len = sizeof(buf); len = recvmsg(hnd->fd, &msg, 0); if (len < 0) return errno; if (!len) return EPIPE; if (sa.nl_pid) { /* not from the kernel */ continue; } for (n = (struct nlmsghdr *)buf; NLMSG_OK(n, len); n = NLMSG_NEXT(n, len)) { if (n->nlmsg_pid != hnd->pid || n->nlmsg_seq != hnd->seq) continue; if (is_dump && n->nlmsg_type == NLMSG_DONE) return 0; if (n->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *nlerr = (struct nlmsgerr *)NLMSG_DATA(n); err = -nlerr->error; goto err_out; } entry = malloc(n->nlmsg_len + sizeof(void *)); if (!entry) { err = ENOMEM; goto err_out; } entry->next = NULL; memcpy(&entry->h, n, n->nlmsg_len); if (!*dest) *dest = entry; else ptr->next = entry; ptr = entry; if (!is_dump) return 0; } } err_out: nlmsg_free(*dest); *dest = NULL; return err; } int nl_exchange(struct nl_handle *hnd, struct nlmsghdr *src, struct nlmsg_entry **dest) { struct iovec iov = { .iov_base = src, .iov_len = src->nlmsg_len, }; int is_dump; int err; is_dump = !!(src->nlmsg_flags & NLM_F_DUMP); err = nl_send(hnd, &iov, 1); if (err) return err; return nl_recv(hnd, dest, is_dump); } /* The original payload is not freed. Returns 0 in case of error, length * of *dest otherwise. *dest is newly allocated. */ int nla_add_str(void *orig, int orig_len, int nla_type, const char *str, void **dest) { struct nlattr *nla; int len = strlen(str) + 1; int size; size = NLA_ALIGN(orig_len) + NLA_HDRLEN + NLA_ALIGN(len); *dest = calloc(size, 1); if (!*dest) return 0; if (orig_len) memcpy(*dest, orig, orig_len); nla = *dest + NLA_ALIGN(orig_len); nla->nla_len = NLA_HDRLEN + len; nla->nla_type = nla_type; memcpy(nla + 1, str, len); return size; } int rtnl_open(struct nl_handle *hnd) { return nl_open(hnd, NETLINK_ROUTE); } int rtnl_dump(struct nl_handle *hnd, int family, int type, struct nlmsg_entry **dest) { struct { struct nlmsghdr n; struct ifinfomsg i; } req; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = sizeof(req); req.n.nlmsg_type = type; req.n.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; req.i.ifi_family = family; return nl_exchange(hnd, &req.n, dest); } void rtnl_parse(struct rtattr *tb[], int max, struct rtattr *rta, int len) { memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); while (RTA_OK(rta, len)) { if (rta->rta_type <= max) tb[rta->rta_type] = rta; rta = RTA_NEXT(rta, len); } } void rtnl_parse_nested(struct rtattr *tb[], int max, struct rtattr *rta) { rtnl_parse(tb, max, RTA_DATA(rta), RTA_PAYLOAD(rta)); } int genl_open(struct nl_handle *hnd) { return nl_open(hnd, NETLINK_GENERIC); } int genl_request(struct nl_handle *hnd, int type, int cmd, void *payload, int payload_len, struct nlmsg_entry **dest) { struct { struct nlmsghdr n; struct genlmsghdr g; } req; struct iovec iov[2]; int err; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = sizeof(req) + payload_len; req.n.nlmsg_type = type; req.n.nlmsg_flags = NLM_F_REQUEST; req.g.cmd = cmd; req.g.version = 1; iov[0].iov_base = &req; iov[0].iov_len = sizeof(req); iov[1].iov_base = payload; iov[1].iov_len = payload_len; err = nl_send(hnd, iov, 2); if (err) return err; return nl_recv(hnd, dest, 0); } unsigned int genl_family_id(struct nl_handle *hnd, const char *name) { unsigned int res = 0; struct nlattr *nla; int len; struct nlmsg_entry *dest; void *ptr; len = nla_add_str(NULL, 0, CTRL_ATTR_FAMILY_NAME, name, &ptr); if (!len) return 0; if (genl_request(hnd, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, ptr, len, &dest)) { free(ptr); return 0; } free(ptr); len = dest->h.nlmsg_len - NLMSG_HDRLEN - GENL_HDRLEN; ptr = (void *)&dest->h + NLMSG_HDRLEN + GENL_HDRLEN; while (len > NLA_HDRLEN) { nla = ptr; if (nla->nla_type == CTRL_ATTR_FAMILY_ID && nla->nla_len >= NLA_HDRLEN + 2) { res = *(uint16_t *)(nla + 1); break; } ptr += NLMSG_ALIGN(nla->nla_len); len -= NLMSG_ALIGN(nla->nla_len); } nlmsg_free(dest); return res; }
/* ====================================================================== */ int getifaddrs(struct ifaddrs **ifap) { int sd; struct nlmsg_list *nlmsg_list, *nlmsg_end, *nlm; /* - - - - - - - - - - - - - - - */ int icnt; size_t dlen, xlen, nlen; uint32_t max_ifindex = 0; pid_t pid = getpid(); int seq; int result; int build ; /* 0 or 1 */ /* ---------------------------------- */ /* initialize */ icnt = dlen = xlen = nlen = 0; nlmsg_list = nlmsg_end = NULL; if (ifap) *ifap = NULL; /* ---------------------------------- */ /* open socket and bind */ sd = nl_open(); if (sd < 0) return -1; /* ---------------------------------- */ /* gather info */ if ((seq = nl_getlist(sd, 0, RTM_GETLINK, &nlmsg_list, &nlmsg_end)) < 0){ free_nlmsglist(nlmsg_list); nl_close(sd); return -1; } if ((seq = nl_getlist(sd, seq+1, RTM_GETADDR, &nlmsg_list, &nlmsg_end)) < 0){ free_nlmsglist(nlmsg_list); nl_close(sd); return -1; } /* ---------------------------------- */ /* Estimate size of result buffer and fill it */ for (build=0; build<=1; build++){ struct ifaddrs *ifl = NULL, *ifa = NULL; struct nlmsghdr *nlh, *nlh0; void *data = NULL, *xdata = NULL, *ifdata = NULL; char *ifname = NULL, **iflist = NULL; uint16_t *ifflist = NULL; struct rtmaddr_ifamap ifamap; if (build){ ifa = data = calloc(1, NLMSG_ALIGN(sizeof(struct ifaddrs[icnt])) + dlen + xlen + nlen); ifdata = calloc(1, NLMSG_ALIGN(sizeof(char *[max_ifindex+1])) + NLMSG_ALIGN(sizeof(uint16_t [max_ifindex+1]))); if (ifap != NULL) *ifap = (ifdata != NULL) ? ifa : NULL; else{ free_data(data, ifdata); result = 0; break; } if (data == NULL || ifdata == NULL){ free_data(data, ifdata); result = -1; break; } ifl = NULL; data += NLMSG_ALIGN(sizeof(struct ifaddrs)) * icnt; xdata = data + dlen; ifname = xdata + xlen; iflist = ifdata; ifflist = ((void *)iflist) + NLMSG_ALIGN(sizeof(char *[max_ifindex+1])); } for (nlm=nlmsg_list; nlm; nlm=nlm->nlm_next){ int nlmlen = nlm->size; if (!(nlh0 = nlm->nlh)) continue; for (nlh = nlh0; NLMSG_OK(nlh, nlmlen); nlh=NLMSG_NEXT(nlh,nlmlen)){ struct ifinfomsg *ifim = NULL; struct ifaddrmsg *ifam = NULL; struct rtattr *rta; size_t nlm_struct_size = 0; sa_family_t nlm_family = 0; uint32_t nlm_scope = 0, nlm_index = 0; #ifndef IFA_NETMASK size_t sockaddr_size = 0; uint32_t nlm_prefixlen = 0; #endif size_t rtasize; memset(&ifamap, 0, sizeof(ifamap)); /* check if the message is what we want */ if (nlh->nlmsg_pid != pid || nlh->nlmsg_seq != nlm->seq) continue; if (nlh->nlmsg_type == NLMSG_DONE){ break; /* ok */ } switch (nlh->nlmsg_type){ case RTM_NEWLINK: ifim = (struct ifinfomsg *)NLMSG_DATA(nlh); nlm_struct_size = sizeof(*ifim); nlm_family = ifim->ifi_family; nlm_scope = 0; nlm_index = ifim->ifi_index; nlm_prefixlen = 0; if (build) ifflist[nlm_index] = ifa->ifa_flags = ifim->ifi_flags; break; case RTM_NEWADDR: ifam = (struct ifaddrmsg *)NLMSG_DATA(nlh); nlm_struct_size = sizeof(*ifam); nlm_family = ifam->ifa_family; nlm_scope = ifam->ifa_scope; nlm_index = ifam->ifa_index; nlm_prefixlen = ifam->ifa_prefixlen; if (build) ifa->ifa_flags = ifflist[nlm_index]; break; default: continue; } if (!build){ if (max_ifindex < nlm_index) max_ifindex = nlm_index; } else { if (ifl != NULL) ifl->ifa_next = ifa; } rtasize = NLMSG_PAYLOAD(nlh, nlmlen) - NLMSG_ALIGN(nlm_struct_size); for (rta = (struct rtattr *)(((char *)NLMSG_DATA(nlh)) + NLMSG_ALIGN(nlm_struct_size)); RTA_OK(rta, rtasize); rta = RTA_NEXT(rta, rtasize)){ struct sockaddr **sap = NULL; void *rtadata = RTA_DATA(rta); size_t rtapayload = RTA_PAYLOAD(rta); socklen_t sa_len; switch(nlh->nlmsg_type){ case RTM_NEWLINK: switch(rta->rta_type){ case IFLA_ADDRESS: case IFLA_BROADCAST: if (build){ sap = (rta->rta_type == IFLA_ADDRESS) ? &ifa->ifa_addr : &ifa->ifa_broadaddr; *sap = (struct sockaddr *)data; } sa_len = ifa_sa_len(AF_PACKET, rtapayload); if (rta->rta_type == IFLA_ADDRESS) sockaddr_size = NLMSG_ALIGN(sa_len); if (!build){ dlen += NLMSG_ALIGN(sa_len); } else { memset(*sap, 0, sa_len); ifa_make_sockaddr(AF_PACKET, *sap, rtadata,rtapayload, 0,0); ((struct sockaddr_ll *)*sap)->sll_ifindex = nlm_index; ((struct sockaddr_ll *)*sap)->sll_hatype = ifim->ifi_type; data += NLMSG_ALIGN(sa_len); } break; case IFLA_IFNAME:/* Name of Interface */ if (!build) nlen += NLMSG_ALIGN(rtapayload + 1); else{ ifa->ifa_name = ifname; if (iflist[nlm_index] == NULL) iflist[nlm_index] = ifa->ifa_name; strncpy(ifa->ifa_name, rtadata, rtapayload); ifa->ifa_name[rtapayload] = '\0'; ifname += NLMSG_ALIGN(rtapayload + 1); } break; case IFLA_STATS:/* Statistics of Interface */ if (!build) xlen += NLMSG_ALIGN(rtapayload); else{ ifa->ifa_data = xdata; memcpy(ifa->ifa_data, rtadata, rtapayload); xdata += NLMSG_ALIGN(rtapayload); } break; case IFLA_UNSPEC: break; case IFLA_MTU: break; case IFLA_LINK: break; case IFLA_QDISC: break; } break; case RTM_NEWADDR: if (nlm_family == AF_PACKET) break; switch(rta->rta_type){ case IFA_ADDRESS: ifamap.address = rtadata; ifamap.address_len = rtapayload; break; case IFA_LOCAL: ifamap.local = rtadata; ifamap.local_len = rtapayload; break; case IFA_BROADCAST: ifamap.broadcast = rtadata; ifamap.broadcast_len = rtapayload; break; #ifdef HAVE_IFADDRS_IFA_ANYCAST case IFA_ANYCAST: ifamap.anycast = rtadata; ifamap.anycast_len = rtapayload; break; #endif case IFA_LABEL: if (!build) nlen += NLMSG_ALIGN(rtapayload + 1); else{ ifa->ifa_name = ifname; if (iflist[nlm_index] == NULL) iflist[nlm_index] = ifname; strncpy(ifa->ifa_name, rtadata, rtapayload); ifa->ifa_name[rtapayload] = '\0'; ifname += NLMSG_ALIGN(rtapayload + 1); } break; case IFA_UNSPEC: break; case IFA_CACHEINFO: break; } } } if (nlh->nlmsg_type == RTM_NEWADDR && nlm_family != AF_PACKET) { if (!ifamap.local) { ifamap.local = ifamap.address; ifamap.local_len = ifamap.address_len; } if (!ifamap.address) { ifamap.address = ifamap.local; ifamap.address_len = ifamap.local_len; } if (ifamap.address_len != ifamap.local_len || (ifamap.address != NULL && memcmp(ifamap.address, ifamap.local, ifamap.address_len))) { /* p2p; address is peer and local is ours */ ifamap.broadcast = ifamap.address; ifamap.broadcast_len = ifamap.address_len; ifamap.address = ifamap.local; ifamap.address_len = ifamap.local_len; } if (ifamap.address) { #ifndef IFA_NETMASK sockaddr_size = NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len)); #endif if (!build) dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len)); else { ifa->ifa_addr = (struct sockaddr *)data; ifa_make_sockaddr(nlm_family, ifa->ifa_addr, ifamap.address, ifamap.address_len, nlm_scope, nlm_index); data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.address_len)); } } #ifdef IFA_NETMASK if (ifamap.netmask) { if (!build) dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.netmask_len)); else { ifa->ifa_netmask = (struct sockaddr *)data; ifa_make_sockaddr(nlm_family, ifa->ifa_netmask, ifamap.netmask, ifamap.netmask_len, nlm_scope, nlm_index); data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.netmask_len)); } } #endif if (ifamap.broadcast) { if (!build) dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.broadcast_len)); else { ifa->ifa_broadaddr = (struct sockaddr *)data; ifa_make_sockaddr(nlm_family, ifa->ifa_broadaddr, ifamap.broadcast, ifamap.broadcast_len, nlm_scope, nlm_index); data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.broadcast_len)); } } #ifdef HAVE_IFADDRS_IFA_ANYCAST if (ifamap.anycast) { if (!build) dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.anycast_len)); else { ifa->ifa_anycast = (struct sockaddr *)data; ifa_make_sockaddr(nlm_family, ifa->ifa_anyaddr, ifamap.anycast, ifamap.anycast_len, nlm_scope, nlm_index); data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.anycast_len)); } } #endif } if (!build){ #ifndef IFA_NETMASK dlen += sockaddr_size; #endif icnt++; } else { if (ifa->ifa_name == NULL) ifa->ifa_name = iflist[nlm_index]; #ifndef IFA_NETMASK if (ifa->ifa_addr && ifa->ifa_addr->sa_family != AF_UNSPEC && ifa->ifa_addr->sa_family != AF_PACKET){ ifa->ifa_netmask = (struct sockaddr *)data; ifa_make_sockaddr_mask(ifa->ifa_addr->sa_family, ifa->ifa_netmask, nlm_prefixlen); } data += sockaddr_size; #endif ifl = ifa++; } } } if (!build){ if (icnt == 0 && (dlen + nlen + xlen == 0)){ if (ifap != NULL) *ifap = NULL; break; /* cannot found any addresses */ } } else free_data(NULL, ifdata); } /* ---------------------------------- */ /* Finalize */ free_nlmsglist(nlmsg_list); nl_close(sd); return 0; }
nfct_t *nfct_create(ginkgo_ctx *ctx, int grps, nfct_notify cb, void *ud) { nfct_t *ct; char name[20]; ginkgo_src src = { .name = name, .fd = -1, .rd = NULL, .wr = NULL, .pars = nl_parse, .resp = nfct_response, .hand = nfct_handler, .ud = NULL, }; int fd; if(! ctx) return NULL; if((fd = nl_open(NETLINK_NETFILTER, grps)) < 0) return NULL; if(! instantiate(ct)) { close(fd); return NULL; } ct->ginkgo = ctx; ct->nlfd = fd; ct->nlgrps = grps; ct->nlseq = 0; ct->cb = cb; ct->ud = ud; src.fd = fd; src.ud = ct; sprintf(name, "nfct-%d", fd); if(ginkgo_src_register(ctx, &src, &ct->id, 0) < 0) { close(fd); free(ct); return NULL; } return ct; } void nfct_destroy(nfct_t *ct) { if(ct) { ginkgo_src_deregister(ct->ginkgo, ct->id, 1, 1); close(ct->nlfd); free(ct); } } int nfct_conn_get_counter(const conn_entry *e, conn_counter *counter) { const struct nlattr *orig = e->nla[CTA_COUNTERS_ORIG]; const struct nlattr *rep = e->nla[CTA_COUNTERS_REPLY]; struct nlattr *arr[CTA_COUNTERS_MAX + 1]; if(orig && rep) { nla_parse_nested(arr, CTA_COUNTERS_MAX, orig); if(! arr[CTA_COUNTERS_PACKETS] || ! arr[CTA_COUNTERS_BYTES]) return -1; counter->orig_pkts = be64toh(nla_get_be64(arr[CTA_COUNTERS_PACKETS])); counter->orig_bytes = be64toh(nla_get_be64(arr[CTA_COUNTERS_BYTES])); nla_parse_nested(arr, CTA_COUNTERS_MAX, rep); if(! arr[CTA_COUNTERS_PACKETS] || ! arr[CTA_COUNTERS_BYTES]) return -1; counter->rep_pkts = be64toh(nla_get_be64(arr[CTA_COUNTERS_PACKETS])); counter->rep_bytes = be64toh(nla_get_be64(arr[CTA_COUNTERS_BYTES])); return 0; } return -1; } int nfct_conn_get_tcpinfo(const conn_entry *e, conn_tcpinfo *info) { const struct nlattr *proto = e->nla[CTA_PROTOINFO]; const struct nlattr *tcp; struct nlattr *arr[CTA_PROTOINFO_TCP_MAX + 1]; if(proto) { tcp = (const struct nlattr *)nla_data(proto); if(nla_type(tcp) != CTA_PROTOINFO_TCP) return -1; nla_parse_nested(arr, CTA_PROTOINFO_TCP_MAX, tcp); if(arr[CTA_PROTOINFO_TCP_STATE] || arr[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL] || arr[CTA_PROTOINFO_TCP_WSCALE_REPLY] || arr[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL] || arr[CTA_PROTOINFO_TCP_FLAGS_REPLY]) { info->state = nla_get_u8(arr[CTA_PROTOINFO_TCP_STATE]); info->wscale_orig = nla_get_u8(arr[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL]); info->wscale_rep = nla_get_u8(arr[CTA_PROTOINFO_TCP_WSCALE_REPLY]); nla_get_mem(arr[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL], &info->flags_orig, sizeof(info->flags_orig)); nla_get_mem(arr[CTA_PROTOINFO_TCP_FLAGS_REPLY], &info->flags_rep, sizeof(info->flags_rep)); return 0; } } return -1; } int nfct_conn_get_sctpinfo(const conn_entry *e, conn_sctpinfo *info) { const struct nlattr *proto = e->nla[CTA_PROTOINFO]; const struct nlattr *sctp; struct nlattr *arr[CTA_PROTOINFO_SCTP_MAX + 1]; if(proto) { sctp = (const struct nlattr *)nla_data(proto); if(nla_type(sctp) != CTA_PROTOINFO_SCTP) return -1; nla_parse_nested(arr, CTA_PROTOINFO_SCTP_MAX, sctp); if(! arr[CTA_PROTOINFO_SCTP_STATE] || ! arr[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL] || ! arr[CTA_PROTOINFO_SCTP_VTAG_REPLY]) { info->state = nla_get_u8(arr[CTA_PROTOINFO_SCTP_STATE]); info->vtag_orig = ntohl(nla_get_u8(arr[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL])); info->vtag_rep = ntohl(nla_get_u8(arr[CTA_PROTOINFO_SCTP_VTAG_REPLY])); return 0; } } return -1; } int __nfct_conn_get_tuple(const conn_entry *e, int type, conn_tuple *tuple) { struct nlattr *arr[CTA_TUPLE_MAX + 1]; struct nlattr *ip[CTA_IP_MAX + 1]; struct nlattr *proto[CTA_PROTO_MAX + 1]; if(! e->nla[type]) return -1; memset(tuple, 0, sizeof(*tuple)); nla_parse_nested(arr, CTA_TUPLE_MAX, e->nla[type]); if(! arr[CTA_TUPLE_IP] || ! arr[CTA_TUPLE_PROTO]) { PR_WARN("unexpected NULL tuple IP or proto"); return-1; } nla_parse_nested(ip, CTA_IP_MAX, arr[CTA_TUPLE_IP]); tuple->src.l3num = e->l3num; if(e->l3num == AF_INET) { if(! ip[CTA_IP_V4_SRC] || ! ip[CTA_IP_V4_DST]) return -1; tuple->src.u3.ip = nla_get_be32(ip[CTA_IP_V4_SRC]); tuple->dst.u3.ip = nla_get_be32(ip[CTA_IP_V4_DST]); }else if(e->l3num == AF_INET6) { if(! ip[CTA_IP_V6_SRC] || ! ip[CTA_IP_V6_DST]) return -1; nla_get_mem(ip[CTA_IP_V6_SRC], &tuple->src.u3.in6, sizeof(tuple->src.u3.in6)); nla_get_mem(ip[CTA_IP_V6_DST], &tuple->dst.u3.in6, sizeof(tuple->dst.u3.in6)); }else { PR_WARN("unexpected l3num while parsing tuple:%d", e->l3num); return -1; } nla_parse_nested(proto, CTA_PROTO_MAX, arr[CTA_TUPLE_PROTO]); if(! proto[CTA_PROTO_NUM]) { PR_WARN("unexpected NULL proto num while parsing tuple"); return -1; } tuple->dst.protonum = nla_get_u8(proto[CTA_PROTO_NUM]); switch(tuple->dst.protonum) { case IPPROTO_TCP: case IPPROTO_UDP: case IPPROTO_UDPLITE: if(! proto[CTA_PROTO_SRC_PORT] || ! proto[CTA_PROTO_DST_PORT]) { PR_WARN("unexpected NULL port while parsing tuple"); return -1; } tuple->src.u.tcp.port = nla_get_be16(proto[CTA_PROTO_SRC_PORT]); tuple->dst.u.tcp.port = nla_get_be16(proto[CTA_PROTO_DST_PORT]); break; case IPPROTO_ICMP: if(! proto[CTA_PROTO_ICMP_ID] || ! proto[CTA_PROTO_ICMP_TYPE] || ! proto[CTA_PROTO_ICMP_CODE]) { PR_WARN("unexpected NULL icmp attr while parsing tuple"); return -1; } tuple->src.u.icmp.id = nla_get_be16(proto[CTA_PROTO_ICMP_ID]); tuple->dst.u.icmp.type = nla_get_u8(proto[CTA_PROTO_ICMP_TYPE]); tuple->dst.u.icmp.code = nla_get_u8(proto[CTA_PROTO_ICMP_CODE]); break; case IPPROTO_ICMPV6: if(! proto[CTA_PROTO_ICMPV6_ID] || ! proto[CTA_PROTO_ICMPV6_TYPE] || ! proto[CTA_PROTO_ICMPV6_CODE]) { PR_WARN("unexpected NULL icmpv6 attr while parsing tuple"); return -1; } tuple->src.u.icmp.id = nla_get_be16(proto[CTA_PROTO_ICMPV6_ID]); tuple->dst.u.icmp.type = nla_get_u8(proto[CTA_PROTO_ICMPV6_TYPE]); tuple->dst.u.icmp.code = nla_get_u8(proto[CTA_PROTO_ICMPV6_CODE]); break; default: PR_INFO("unsupported proto %d while parsing tuple", tuple->dst.protonum); return -1; } return 0; } /* fixme: nat seq adj */ nfct_msg *nfct_msg_new(__u8 l3num, int flags) { ginkgo_msg *msg; struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; nfct_msg_ctl *ctl; conn_entry *e; if((msg = ginkgo_new_msg(0, NFCT_MSG_GOOD_SIZE))) { if(! instantiate(e)) { free(msg); return NULL; } nlh = NL_HEADER(msg); BZERO(nlh); nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; if(flags & NFCT_F_CREATE) nlh->nlmsg_flags |= NLM_F_CREATE; if(flags & NFCT_F_EXCL) nlh->nlmsg_flags |= NLM_F_EXCL; if(flags & NFCT_F_DUMP) nlh->nlmsg_flags |= NLM_F_DUMP; nfmsg = (struct nfgenmsg *)NLMSG_DATA(nlh); nfmsg->nfgen_family = l3num; nfmsg->version = NFNETLINK_V0; nfmsg->res_id = 0; BZERO(e); e->l3num = l3num; ctl = msg_ctl(msg); BZERO(ctl); ctl->base.entry = e; ctl->ctx = (char *)nfmsg + NLMSG_ALIGN(sizeof(struct nfgenmsg)); ctl->sz = NFCT_MSG_GOOD_SIZE; return (nfct_msg *)ctl; } return NULL; }
void setup_netif(struct netif *ifs, pid_t pid) { int rc; _close_ int sock = nl_open(); struct netif *i = NULL; DL_FOREACH(ifs, i) { unsigned int if_index = 0; switch (i->type) { case MACVLAN: { _free_ char *name = NULL; rc = asprintf(&name, "pflask-%d", pid); fail_if(rc < 0, "OOM"); if_index = if_nametoindex(i->dev); sys_fail_if(!if_index, "Error searching for '%s'", i->dev); create_macvlan(sock, if_index, name); if_index = if_nametoindex(name); break; } case IPVLAN: { _free_ char *name = NULL; rc = asprintf(&name, "pflask-%d", pid); fail_if(rc < 0, "OOM"); if_index = if_nametoindex(i->dev); sys_fail_if(!if_index, "Error searching for '%s'", i->dev); create_ipvlan(sock, if_index, name); if_index = if_nametoindex(name); break; } case VETH: { _free_ char *name = NULL; rc = asprintf(&name, "pflask-%d", pid); fail_if(rc < 0, "OOM"); create_veth_pair(sock, i->dev, name); if_index = if_nametoindex(name); sys_fail_if(!if_index, "Error searching for '%s'", name); break; } case MOVE: if_index = if_nametoindex(i->dev); sys_fail_if(!if_index, "Error searching for '%s'", i->dev); break; } move_and_rename_if(sock, pid, if_index, i->name); }
/* ====================================================================== */ int ni_ifaddrs(struct ni_ifaddrs **ifap, sa_family_t family) { int sd; struct nlmsg_list *nlmsg_list, *nlmsg_end, *nlm; /* - - - - - - - - - - - - - - - */ int icnt; size_t dlen, xlen; uint32_t max_ifindex = 0; pid_t pid = getpid(); int seq = 0; int result; int build; /* 0 or 1 */ /* ---------------------------------- */ /* initialize */ icnt = dlen = xlen = 0; nlmsg_list = nlmsg_end = NULL; if (ifap) *ifap = NULL; /* ---------------------------------- */ /* open socket and bind */ sd = nl_open(); if (sd < 0) return -1; /* ---------------------------------- */ /* gather info */ if ((seq = nl_getlist(sd, seq + 1, RTM_GETADDR, &nlmsg_list, &nlmsg_end)) < 0) { free_nlmsglist(nlmsg_list); nl_close(sd); return -1; } /* ---------------------------------- */ /* Estimate size of result buffer and fill it */ for (build = 0; build <= 1; build++) { struct ni_ifaddrs *ifl = NULL, *ifa = NULL; struct nlmsghdr *nlh, *nlh0; void *data = NULL, *xdata = NULL; uint16_t *ifflist = NULL; #ifndef IFA_LOCAL struct rtmaddr_ifamap ifamap; #endif if (build) { ifa = data = calloc(1, NLMSG_ALIGN(sizeof(struct ni_ifaddrs[icnt])) + dlen + xlen); if (ifap != NULL) *ifap = ifa; else { free_data(data); result = 0; break; } if (data == NULL) { free_data(data); result = -1; break; } ifl = NULL; data += NLMSG_ALIGN(sizeof(struct ni_ifaddrs)) * icnt; xdata = data + dlen; ifflist = xdata + xlen; } for (nlm = nlmsg_list; nlm; nlm = nlm->nlm_next) { int nlmlen = nlm->size; if (!(nlh0 = nlm->nlh)) continue; for (nlh = nlh0; NLMSG_OK(nlh, nlmlen); nlh = NLMSG_NEXT(nlh, nlmlen)) { struct ifaddrmsg *ifam = NULL; struct rtattr *rta; size_t nlm_struct_size = 0; sa_family_t nlm_family = 0; uint32_t nlm_scope = 0, nlm_index = 0; unsigned int nlm_flags; size_t rtasize; #ifndef IFA_LOCAL memset(&ifamap, 0, sizeof(ifamap)); #endif /* check if the message is what we want */ if (nlh->nlmsg_pid != pid || nlh->nlmsg_seq != nlm->seq) continue; if (nlh->nlmsg_type == NLMSG_DONE) { break; /* ok */ } switch (nlh->nlmsg_type) { case RTM_NEWADDR: ifam = (struct ifaddrmsg *) NLMSG_DATA(nlh); nlm_struct_size = sizeof(*ifam); nlm_family = ifam->ifa_family; nlm_scope = ifam->ifa_scope; nlm_index = ifam->ifa_index; nlm_flags = ifam->ifa_flags; if (family && nlm_family != family) continue; if (build) { ifa->ifa_ifindex = nlm_index; ifa->ifa_flags = nlm_flags; } break; default: continue; } if (!build) { if (max_ifindex < nlm_index) max_ifindex = nlm_index; } else { if (ifl != NULL) ifl->ifa_next = ifa; } rtasize = NLMSG_PAYLOAD(nlh, nlmlen) - NLMSG_ALIGN(nlm_struct_size); for (rta = (struct rtattr *) (((char *) NLMSG_DATA(nlh)) + NLMSG_ALIGN(nlm_struct_size)); RTA_OK(rta, rtasize); rta = RTA_NEXT(rta, rtasize)) { void *rtadata = RTA_DATA(rta); size_t rtapayload = RTA_PAYLOAD(rta); switch (nlh->nlmsg_type) { case RTM_NEWADDR: if (nlm_family == AF_PACKET) break; switch (rta->rta_type) { #ifndef IFA_LOCAL case IFA_ADDRESS: ifamap.address = rtadata; ifamap.address_len = rtapayload; break; case IFA_LOCAL: ifamap.local = rtadata; ifamap.local_len = rtapayload; break; case IFA_BROADCAST: ifamap.broadcast = rtadata; ifamap.broadcast_len = rtapayload; break; case IFA_LABEL: break; case IFA_UNSPEC: break; #else case IFA_LOCAL: if (!build) dlen += NLMSG_ALIGN(rtapayload); else { memcpy(data, rtadata, rtapayload); ifa->ifa_addr = data; data += NLMSG_ALIGN(rtapayload); } break; #endif case IFA_CACHEINFO: if (!build) xlen += NLMSG_ALIGN(rtapayload); else { memcpy(xdata, rtadata, rtapayload); ifa->ifa_cacheinfo = xdata; xdata += NLMSG_ALIGN(rtapayload); } break; } } } #ifndef IFA_LOCAL if (nlh->nlmsg_type == RTM_NEWADDR && nlm_family != AF_PACKET) { if (!ifamap.local) { ifamap.local = ifamap.address; ifamap.local_len = ifamap.address_len; } if (!ifamap.address) { ifamap.address = ifamap.local; ifamap.address_len = ifamap.local_len; } if (ifamap.address_len != ifamap.local_len || (ifamap.address != NULL && memcmp(ifamap.address, ifamap.local, ifamap.address_len))) { /* p2p; address is peer and local is ours */ ifamap.broadcast = ifamap.address; ifamap.broadcast_len = ifamap.address_len; ifamap.address = ifamap.local; ifamap.address_len = ifamap.local_len; } if (ifamap.address) { if (!build) dlen += NLMSG_ALIGN(ifamap.address_len); else { ifa->ifa_addr = (struct sockaddr *) data; memcpy(ifa->ifa_addr, ifamap.address, ifamap.address_len); data += NLMSG_ALIGN(ifamap.address_len); } } } #endif if (!build) { icnt++; } else { ifl = ifa++; } } } if (!build) { if (icnt == 0 && (dlen + xlen == 0)) { if (ifap != NULL) *ifap = NULL; break; /* cannot found any addresses */ } } } /* ---------------------------------- */ /* Finalize */ free_nlmsglist(nlmsg_list); nl_close(sd); return 0; }
int main(int argc, char **argv) { int ch, longindex, nr; int is_daemon = 1, is_debug = 1; pid_t pid; struct pollfd *poll_array; while ((ch = getopt_long(argc, argv, "fd:vh", long_options, &longindex)) >= 0) { switch (ch) { case 'f': is_daemon = 0; break; case 'd': is_debug = atoi(optarg); break; case 'v': exit(0); break; case 'h': usage(0); break; default: usage(1); break; } } init(is_daemon, is_debug); if (is_daemon) { pid = fork(); if (pid < 0) exit(-1); else if (pid) exit(0); chdir("/"); close(0); open("/dev/null", O_RDWR); dup2(0, 1); dup2(0, 2); setsid(); } nl_fd = nl_open(); if (nl_fd < 0) exit(nl_fd); ipc_fd = ipc_open(); if (ipc_fd < 0) exit(ipc_fd); dl_init(); nr = MAX_DL_HANDLES; poll_array = poll_init(nr); dl_config_load(); event_loop(nr, poll_array); return 0; }
int main(int argc,char **argv) { int status; int fd; struct msghdr msg; struct sockaddr_nl dest_addr; struct nlmsghdr *nlh; struct iovec iov; struct dad_failed_msg_t *dad_msg; fd = nl_open(); if (fd < 0) { perror("Error\n"); return -1; } nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(sizeof(struct dad_failed_msg_t))); if (!nlh) { perror("Malloc Error\n"); return -1; } memset(nlh, 0, NLMSG_SPACE(sizeof(struct dad_failed_msg_t))); iov.iov_base = (void *)nlh; iov.iov_len = NLMSG_SPACE(sizeof(struct dad_failed_msg_t)); msg.msg_name = (void *)&dest_addr; msg.msg_namelen = sizeof(dest_addr); msg.msg_iov = &iov; msg.msg_iovlen = 1; printf("Starting recv,iov length is %d\n",(int)iov.iov_len); while (1) { status = recvmsg(fd, &msg, 0); if (status < 0) { close(fd); free(nlh); perror("recv"); return 1; } if (iov.iov_len == nlh->nlmsg_len) { dad_msg = (struct dad_failed_msg_t *)NLMSG_DATA(nlh); #define ADDR_PREFIX_FMT "%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X/%d" #define ADDR_PREFIX_PARAM(dad_msg) dad_msg->addr.s6_addr16[0],\ dad_msg->addr.s6_addr16[1],\ dad_msg->addr.s6_addr16[2],\ dad_msg->addr.s6_addr16[3],\ dad_msg->addr.s6_addr16[4],\ dad_msg->addr.s6_addr16[5],\ dad_msg->addr.s6_addr16[6],\ dad_msg->addr.s6_addr16[7],\ dad_msg->prefix_len printf("DAD failed on interface %s,Address:" ADDR_PREFIX_FMT "\n", dad_msg->name,ADDR_PREFIX_PARAM(dad_msg)); } } close(fd); free(nlh); return 0; }