void __build_tuple_ip(struct nfnlhdr *req, size_t size, const struct __nfct_tuple *t) { struct nfattr *nest; nest = nfnl_nest(&req->nlh, size, CTA_TUPLE_IP); switch(t->l3protonum) { case AF_INET: nfnl_addattr_l(&req->nlh, size, CTA_IP_V4_SRC, &t->src.v4, sizeof(u_int32_t)); nfnl_addattr_l(&req->nlh, size, CTA_IP_V4_DST, &t->dst.v4, sizeof(u_int32_t)); break; case AF_INET6: nfnl_addattr_l(&req->nlh, size, CTA_IP_V6_SRC, &t->src.v6, sizeof(struct in6_addr)); nfnl_addattr_l(&req->nlh, size, CTA_IP_V6_DST, &t->dst.v6, sizeof(struct in6_addr)); break; default: break; } nfnl_nest_end(&req->nlh, nest); }
static void build_tuple_proto(struct nfnlhdr *req, int size, struct nfct_tuple *t) { nfnl_addattr_l(&req->nlh, size, CTA_IP_V4_SRC, &t->src.v4, sizeof(u_int32_t)); nfnl_addattr_l(&req->nlh, size, CTA_IP_V4_DST, &t->dst.v4, sizeof(u_int32_t)); }
static void build_tuple_proto(struct nfnlhdr *req, int size, struct nfct_tuple *t) { nfnl_addattr_l(&req->nlh, size, CTA_PROTO_SRC_PORT, &t->l4src.sctp.port, sizeof(u_int16_t)); nfnl_addattr_l(&req->nlh, size, CTA_PROTO_DST_PORT, &t->l4dst.sctp.port, sizeof(u_int16_t)); }
static void build_tuple_proto(struct nfnlhdr *req, int size, struct nfct_tuple *t) { nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_CODE, &t->l4dst.icmp.code, sizeof(u_int8_t)); nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_TYPE, &t->l4dst.icmp.type, sizeof(u_int8_t)); nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_ID, &t->l4src.icmp.id, sizeof(u_int16_t)); }
void __build_nat(struct nfnlhdr *req, size_t size, const struct __nfct_nat *nat) { nfnl_addattr_l(&req->nlh, size, CTA_NAT_MINIP, &nat->min_ip, sizeof(u_int32_t)); }
/** * nfnl_addattr8 - Add uint8_t attribute to nlmsghdr * * @n: netlink message header to which attribute is to be added * @maxlen: maximum length of netlink message header * @type: type of new attribute * @data: content of new attribute */ int nfnl_addattr8(struct nlmsghdr *n, int maxlen, int type, uint8_t data) { assert(n); assert(maxlen > 0); assert(type >= 0); return nfnl_addattr_l(n, maxlen, type, &data, sizeof(data)); }
void __build_tuple_proto(struct nfnlhdr *req, size_t size, const struct __nfct_tuple *t) { struct nfattr *nest; nest = nfnl_nest(&req->nlh, size, CTA_TUPLE_PROTO); nfnl_addattr_l(&req->nlh, size, CTA_PROTO_NUM, &t->protonum, sizeof(u_int8_t)); switch(t->protonum) { case IPPROTO_UDP: case IPPROTO_TCP: case IPPROTO_SCTP: case IPPROTO_DCCP: case IPPROTO_GRE: case IPPROTO_UDPLITE: nfnl_addattr_l(&req->nlh, size, CTA_PROTO_SRC_PORT, &t->l4src.tcp.port, sizeof(u_int16_t)); nfnl_addattr_l(&req->nlh, size, CTA_PROTO_DST_PORT, &t->l4dst.tcp.port, sizeof(u_int16_t)); break; case IPPROTO_ICMP: nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_CODE, &t->l4dst.icmp.code, sizeof(u_int8_t)); nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_TYPE, &t->l4dst.icmp.type, sizeof(u_int8_t)); nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_ID, &t->l4src.icmp.id, sizeof(u_int16_t)); break; case IPPROTO_ICMPV6: nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMPV6_CODE, &t->l4dst.icmp.code, sizeof(u_int8_t)); nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMPV6_TYPE, &t->l4dst.icmp.type, sizeof(u_int8_t)); nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMPV6_ID, &t->l4src.icmp.id, sizeof(u_int16_t)); break; default: break; } nfnl_nest_end(&req->nlh, nest); }
void __build_protonat(struct nfnlhdr *req, size_t size, const struct nf_conntrack *ct, const struct __nfct_nat *nat) { struct nfattr *nest; nest = nfnl_nest(&req->nlh, size, CTA_NAT_PROTO); switch (ct->tuple[__DIR_ORIG].protonum) { case IPPROTO_TCP: case IPPROTO_UDP: nfnl_addattr_l(&req->nlh, size, CTA_PROTONAT_PORT_MIN, &nat->l4min.tcp.port, sizeof(u_int16_t)); nfnl_addattr_l(&req->nlh, size, CTA_PROTONAT_PORT_MAX, &nat->l4max.tcp.port, sizeof(u_int16_t)); break; } nfnl_nest_end(&req->nlh, nest); }
void __build_helper_name(struct nfnlhdr *req, size_t size, const struct nf_conntrack *ct) { struct nfattr *nest; nest = nfnl_nest(&req->nlh, size, CTA_HELP); nfnl_addattr_l(&req->nlh, size, CTA_HELP_NAME, ct->helper_name, strlen(ct->helper_name)); nfnl_nest_end(&req->nlh, nest); }
/* build a NFULNL_MSG_CONFIG message */ static int __build_send_cfg_msg(struct nflog_handle *h, u_int8_t command, u_int16_t queuenum, u_int8_t pf) { char buf[NFNL_HEADER_LEN +NFA_LENGTH(sizeof(struct nfulnl_msg_config_cmd))]; struct nfulnl_msg_config_cmd cmd; struct nlmsghdr *nmh = (struct nlmsghdr *) buf; nfnl_fill_hdr(h->nfnlssh, nmh, 0, pf, queuenum, NFULNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK); cmd.command = command; nfnl_addattr_l(nmh, sizeof(buf), NFULA_CFG_CMD, &cmd, sizeof(cmd)); return nfnl_talk(h->nfnlh, nmh, 0, 0, NULL, NULL, NULL); }
int nflog_set_mode(struct nflog_g_handle *gh, u_int8_t mode, u_int32_t range) { char buf[NFNL_HEADER_LEN +NFA_LENGTH(sizeof(struct nfulnl_msg_config_mode))]; struct nfulnl_msg_config_mode params; struct nlmsghdr *nmh = (struct nlmsghdr *) buf; nfnl_fill_hdr(gh->h->nfnlssh, nmh, 0, AF_UNSPEC, gh->id, NFULNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK); params.copy_range = htonl(range); /* copy_range is short */ params.copy_mode = mode; nfnl_addattr_l(nmh, sizeof(buf), NFULA_CFG_MODE, ¶ms, sizeof(params)); return nfnl_talk(gh->h->nfnlh, nmh, 0, 0, NULL, NULL, NULL); }
/* build a NFULNL_MSG_CONFIG message */ static int __build_send_cfg_msg(struct nflog_handle *h, uint8_t command, uint16_t groupnum, uint8_t pf) { union { char buf[NFNL_HEADER_LEN +NFA_LENGTH(sizeof(struct nfulnl_msg_config_cmd))]; struct nlmsghdr nmh; } u; struct nfulnl_msg_config_cmd cmd; nfnl_fill_hdr(h->nfnlssh, &u.nmh, 0, pf, groupnum, NFULNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK); cmd.command = command; nfnl_addattr_l(&u.nmh, sizeof(u), NFULA_CFG_CMD, &cmd, sizeof(cmd)); return nfnl_query(h->nfnlh, &u.nmh); }
/** * nflog_set_mode - set the amount of packet data that nflog copies to userspace * \param qh Netfilter log handle obtained by call to nflog_bind_group(). * \param mode the part of the packet that we are interested in * \param range size of the packet that we want to get * * Sets the amount of data to be copied to userspace for each packet logged * to the given group. * * - NFULNL_COPY_NONE - do not copy any data * - NFULNL_COPY_META - copy only packet metadata * - NFULNL_COPY_PACKET - copy entire packet * * \return -1 on error; >= otherwise. */ int nflog_set_mode(struct nflog_g_handle *gh, uint8_t mode, uint32_t range) { union { char buf[NFNL_HEADER_LEN +NFA_LENGTH(sizeof(struct nfulnl_msg_config_mode))]; struct nlmsghdr nmh; } u; struct nfulnl_msg_config_mode params; nfnl_fill_hdr(gh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, gh->id, NFULNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK); params.copy_range = htonl(range); /* copy_range is short */ params.copy_mode = mode; nfnl_addattr_l(&u.nmh, sizeof(u), NFULA_CFG_MODE, ¶ms, sizeof(params)); return nfnl_query(gh->h->nfnlh, &u.nmh); }
int get_src_for_route_to(const struct sockaddr * dst, void * src, size_t * src_len, int * index) { int fd = -1; struct nlmsghdr *h; int status; struct { struct nlmsghdr n; struct rtmsg r; char buf[1024]; } req; struct sockaddr_nl nladdr; struct iovec iov = { .iov_base = (void*) &req.n, }; struct msghdr msg = { .msg_name = &nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = &iov, .msg_iovlen = 1, }; const struct sockaddr_in * dst4; const struct sockaddr_in6 * dst6; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_GETROUTE; req.r.rtm_family = dst->sa_family; req.r.rtm_table = 0; req.r.rtm_protocol = 0; req.r.rtm_scope = 0; req.r.rtm_type = 0; req.r.rtm_src_len = 0; req.r.rtm_dst_len = 0; req.r.rtm_tos = 0; { char dst_str[128]; sockaddr_to_string(dst, dst_str, sizeof(dst_str)); syslog(LOG_DEBUG, "get_src_for_route_to (%s)", dst_str); } /* add address */ if(dst->sa_family == AF_INET) { dst4 = (const struct sockaddr_in *)dst; nfnl_addattr_l(&req.n, sizeof(req), RTA_DST, &dst4->sin_addr, 4); req.r.rtm_dst_len = 32; } else { dst6 = (const struct sockaddr_in6 *)dst; nfnl_addattr_l(&req.n, sizeof(req), RTA_DST, &dst6->sin6_addr, 16); req.r.rtm_dst_len = 128; } fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (fd < 0) { syslog(LOG_ERR, "socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE) : %m"); return -1; } memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; req.n.nlmsg_seq = 1; iov.iov_len = req.n.nlmsg_len; status = sendmsg(fd, &msg, 0); if (status < 0) { syslog(LOG_ERR, "sendmsg(rtnetlink) : %m"); goto error; } memset(&req, 0, sizeof(req)); for(;;) { iov.iov_len = sizeof(req); status = recvmsg(fd, &msg, 0); if(status < 0) { if (errno == EINTR || errno == EAGAIN) continue; syslog(LOG_ERR, "recvmsg(rtnetlink) %m"); goto error; } if(status == 0) { syslog(LOG_ERR, "recvmsg(rtnetlink) EOF"); goto error; } for (h = (struct nlmsghdr*)&req.n; status >= (int)sizeof(*h); ) { int len = h->nlmsg_len; int l = len - sizeof(*h); if (l<0 || len>status) { if (msg.msg_flags & MSG_TRUNC) { syslog(LOG_ERR, "Truncated message"); } syslog(LOG_ERR, "malformed message: len=%d", len); goto error; } if(nladdr.nl_pid != 0 || h->nlmsg_seq != 1/*seq*/) { syslog(LOG_ERR, "wrong seq = %d\n", h->nlmsg_seq); /* Don't forget to skip that message. */ status -= NLMSG_ALIGN(len); h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); continue; } if(h->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); syslog(LOG_ERR, "NLMSG_ERROR %d : %s", err->error, strerror(-err->error)); goto error; } if(h->nlmsg_type == RTM_NEWROUTE) { struct rtattr * rta; int len = h->nlmsg_len; len -= NLMSG_LENGTH(sizeof(struct rtmsg)); for(rta = RTM_RTA(NLMSG_DATA((h))); RTA_OK(rta, len); rta = RTA_NEXT(rta,len)) { unsigned char * data = RTA_DATA(rta); if(rta->rta_type == RTA_PREFSRC) { if(src_len && src) { if(*src_len < RTA_PAYLOAD(rta)) { syslog(LOG_WARNING, "cannot copy src: %u<%lu", (unsigned)*src_len, RTA_PAYLOAD(rta)); goto error; } *src_len = RTA_PAYLOAD(rta); memcpy(src, data, RTA_PAYLOAD(rta)); } } else if(rta->rta_type == RTA_OIF) { if(index) memcpy(index, data, sizeof(int)); } } close(fd); return 0; } status -= NLMSG_ALIGN(len); h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); } } syslog(LOG_WARNING, "get_src_for_route_to() : src not found"); error: if(fd >= 0) close(fd); return -1; }
static void __build_helper_name(struct nfnlhdr *req, size_t size, const struct nf_expect *exp) { nfnl_addattr_l(&req->nlh, size, CTA_EXPECT_HELP_NAME, exp->helper_name, strlen(exp->helper_name)); }
static void __build_protoinfo(struct nfnlhdr *req, size_t size, const struct nf_conntrack *ct) { struct nfattr *nest, *nest_proto; switch(ct->head.orig.protonum) { case IPPROTO_TCP: /* Preliminary attribute check to avoid sending an empty * CTA_PROTOINFO_TCP nest, which results in EINVAL in * Linux kernel <= 2.6.25. */ if (!(test_bit(ATTR_TCP_STATE, ct->head.set) || test_bit(ATTR_TCP_FLAGS_ORIG, ct->head.set) || test_bit(ATTR_TCP_FLAGS_REPL, ct->head.set) || test_bit(ATTR_TCP_MASK_ORIG, ct->head.set) || test_bit(ATTR_TCP_MASK_REPL, ct->head.set) || test_bit(ATTR_TCP_WSCALE_ORIG, ct->head.set) || test_bit(ATTR_TCP_WSCALE_REPL, ct->head.set))) { break; } nest = nfnl_nest(&req->nlh, size, CTA_PROTOINFO); nest_proto = nfnl_nest(&req->nlh, size, CTA_PROTOINFO_TCP); if (test_bit(ATTR_TCP_STATE, ct->head.set)) nfnl_addattr_l(&req->nlh, size, CTA_PROTOINFO_TCP_STATE, &ct->protoinfo.tcp.state, sizeof(u_int8_t)); if (test_bit(ATTR_TCP_FLAGS_ORIG, ct->head.set) && test_bit(ATTR_TCP_MASK_ORIG, ct->head.set)) nfnl_addattr_l(&req->nlh, size, CTA_PROTOINFO_TCP_FLAGS_ORIGINAL, &ct->protoinfo.tcp.flags[0], sizeof(struct nf_ct_tcp_flags)); if (test_bit(ATTR_TCP_FLAGS_REPL, ct->head.set) && test_bit(ATTR_TCP_MASK_REPL, ct->head.set)) nfnl_addattr_l(&req->nlh, size, CTA_PROTOINFO_TCP_FLAGS_REPLY, &ct->protoinfo.tcp.flags[1], sizeof(struct nf_ct_tcp_flags)); if (test_bit(ATTR_TCP_WSCALE_ORIG, ct->head.set)) nfnl_addattr_l(&req->nlh, size, CTA_PROTOINFO_TCP_WSCALE_ORIGINAL, &ct->protoinfo.tcp.wscale[__DIR_ORIG], sizeof(u_int8_t)); if (test_bit(ATTR_TCP_WSCALE_REPL, ct->head.set)) nfnl_addattr_l(&req->nlh, size, CTA_PROTOINFO_TCP_WSCALE_REPLY, &ct->protoinfo.tcp.wscale[__DIR_REPL], sizeof(u_int8_t)); nfnl_nest_end(&req->nlh, nest_proto); nfnl_nest_end(&req->nlh, nest); break; case IPPROTO_SCTP: /* See comment above on TCP. */ if (!(test_bit(ATTR_SCTP_STATE, ct->head.set) || test_bit(ATTR_SCTP_VTAG_ORIG, ct->head.set) || test_bit(ATTR_SCTP_VTAG_REPL, ct->head.set))) { break; } nest = nfnl_nest(&req->nlh, size, CTA_PROTOINFO); nest_proto = nfnl_nest(&req->nlh, size, CTA_PROTOINFO_SCTP); if (test_bit(ATTR_SCTP_STATE, ct->head.set)) nfnl_addattr_l(&req->nlh, size, CTA_PROTOINFO_SCTP_STATE, &ct->protoinfo.sctp.state, sizeof(u_int8_t)); if (test_bit(ATTR_SCTP_VTAG_ORIG, ct->head.set)) nfnl_addattr32(&req->nlh, size, CTA_PROTOINFO_SCTP_VTAG_ORIGINAL, htonl(ct->protoinfo.sctp.vtag[__DIR_ORIG])); if (test_bit(ATTR_SCTP_VTAG_REPL, ct->head.set)) nfnl_addattr32(&req->nlh, size, CTA_PROTOINFO_SCTP_VTAG_REPLY, htonl(ct->protoinfo.sctp.vtag[__DIR_REPL])); nfnl_nest_end(&req->nlh, nest_proto); nfnl_nest_end(&req->nlh, nest); break; case IPPROTO_DCCP: /* See comment above on TCP. */ if (!(test_bit(ATTR_DCCP_STATE, ct->head.set) || test_bit(ATTR_DCCP_ROLE, ct->head.set) || test_bit(ATTR_DCCP_HANDSHAKE_SEQ, ct->head.set))) { break; } nest = nfnl_nest(&req->nlh, size, CTA_PROTOINFO); nest_proto = nfnl_nest(&req->nlh, size, CTA_PROTOINFO_DCCP); if (test_bit(ATTR_DCCP_STATE, ct->head.set)) nfnl_addattr_l(&req->nlh, size, CTA_PROTOINFO_DCCP_STATE, &ct->protoinfo.dccp.state, sizeof(u_int8_t)); if (test_bit(ATTR_DCCP_ROLE, ct->head.set)) nfnl_addattr_l(&req->nlh, size, CTA_PROTOINFO_DCCP_ROLE, &ct->protoinfo.dccp.role, sizeof(u_int8_t)); if (test_bit(ATTR_DCCP_HANDSHAKE_SEQ, ct->head.set)) { /* FIXME: use __cpu_to_be64() instead which is the * correct operation. This is a semantic abuse but * we have no function to do it in libnfnetlink. */ u_int64_t handshake_seq = __be64_to_cpu(ct->protoinfo.dccp.handshake_seq); nfnl_addattr_l(&req->nlh, size, CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ, &handshake_seq, sizeof(u_int64_t)); } nfnl_nest_end(&req->nlh, nest_proto); nfnl_nest_end(&req->nlh, nest); default: break; } }
static void __build_protoinfo(struct nfnlhdr *req, size_t size, const struct nf_conntrack *ct) { struct nfattr *nest, *nest_proto; switch(ct->tuple[__DIR_ORIG].protonum) { case IPPROTO_TCP: nest = nfnl_nest(&req->nlh, size, CTA_PROTOINFO); nest_proto = nfnl_nest(&req->nlh, size, CTA_PROTOINFO_TCP); if (test_bit(ATTR_TCP_STATE, ct->set)) nfnl_addattr_l(&req->nlh, size, CTA_PROTOINFO_TCP_STATE, &ct->protoinfo.tcp.state, sizeof(u_int8_t)); if (test_bit(ATTR_TCP_FLAGS_ORIG, ct->set) && test_bit(ATTR_TCP_MASK_ORIG, ct->set)) nfnl_addattr_l(&req->nlh, size, CTA_PROTOINFO_TCP_FLAGS_ORIGINAL, &ct->protoinfo.tcp.flags[0], sizeof(u_int16_t)); if (test_bit(ATTR_TCP_FLAGS_REPL, ct->set) && test_bit(ATTR_TCP_MASK_REPL, ct->set)) nfnl_addattr_l(&req->nlh, size, CTA_PROTOINFO_TCP_FLAGS_REPLY, &ct->protoinfo.tcp.flags[1], sizeof(u_int16_t)); nfnl_nest_end(&req->nlh, nest_proto); nfnl_nest_end(&req->nlh, nest); break; case IPPROTO_SCTP: nest = nfnl_nest(&req->nlh, size, CTA_PROTOINFO); nest_proto = nfnl_nest(&req->nlh, size, CTA_PROTOINFO_SCTP); if (test_bit(ATTR_SCTP_STATE, ct->set)) nfnl_addattr_l(&req->nlh, size, CTA_PROTOINFO_SCTP_STATE, &ct->protoinfo.sctp.state, sizeof(u_int8_t)); if (test_bit(ATTR_SCTP_VTAG_ORIG, ct->set)) nfnl_addattr32(&req->nlh, size, CTA_PROTOINFO_SCTP_VTAG_ORIGINAL, htonl(ct->protoinfo.sctp.vtag[__DIR_ORIG])); if (test_bit(ATTR_SCTP_VTAG_REPL, ct->set)) nfnl_addattr32(&req->nlh, size, CTA_PROTOINFO_SCTP_VTAG_REPLY, htonl(ct->protoinfo.sctp.vtag[__DIR_REPL])); nfnl_nest_end(&req->nlh, nest_proto); nfnl_nest_end(&req->nlh, nest); break; case IPPROTO_DCCP: nest = nfnl_nest(&req->nlh, size, CTA_PROTOINFO); nest_proto = nfnl_nest(&req->nlh, size, CTA_PROTOINFO_DCCP); if (test_bit(ATTR_DCCP_STATE, ct->set)) nfnl_addattr_l(&req->nlh, size, CTA_PROTOINFO_DCCP_STATE, &ct->protoinfo.dccp.state, sizeof(u_int8_t)); if (test_bit(ATTR_DCCP_ROLE, ct->set)) nfnl_addattr_l(&req->nlh, size, CTA_PROTOINFO_DCCP_ROLE, &ct->protoinfo.dccp.role, sizeof(u_int8_t)); if (test_bit(ATTR_DCCP_HANDSHAKE_SEQ, ct->set)) { /* FIXME: use __cpu_to_be64() instead which is the * correct operation. This is a semantic abuse but * we have no function to do it in libnfnetlink. */ u_int64_t handshake_seq = __be64_to_cpu(ct->protoinfo.dccp.handshake_seq); nfnl_addattr_l(&req->nlh, size, CTA_PROTOINFO_DCCP_SEQ, &handshake_seq, sizeof(u_int64_t)); } nfnl_nest_end(&req->nlh, nest_proto); nfnl_nest_end(&req->nlh, nest); default: break; } }
static int osf_load_line(char *buffer, int len, int del) { int i, cnt = 0; char obuf[MAXOPTSTRLEN]; struct xt_osf_user_finger f; char *pbeg, *pend; char buf[NFNL_HEADER_LEN + NFA_LENGTH(sizeof(struct xt_osf_user_finger))]; struct nlmsghdr *nmh = (struct nlmsghdr *) buf; memset(&f, 0, sizeof(struct xt_osf_user_finger)); ulog("Loading '%s'.\n", buffer); for (i = 0; i < len && buffer[i] != '\0'; ++i) { if (buffer[i] == ':') cnt++; } if (cnt != 8) { ulog("Wrong input line '%s': cnt: %d, must be 8, i: %d, must be %d.\n", buffer, cnt, i, len); return -EINVAL; } memset(obuf, 0, sizeof(obuf)); pbeg = buffer; pend = xt_osf_strchr(pbeg, OSFPDEL); if (pend) { *pend = '\0'; if (pbeg[0] == 'S') { f.wss.wc = OSF_WSS_MSS; if (pbeg[1] == '%') f.wss.val = strtoul(&pbeg[2], NULL, 10); else if (pbeg[1] == '*') f.wss.val = 0; else f.wss.val = strtoul(&pbeg[1], NULL, 10); } else if (pbeg[0] == 'T') { f.wss.wc = OSF_WSS_MTU; if (pbeg[1] == '%') f.wss.val = strtoul(&pbeg[2], NULL, 10); else if (pbeg[1] == '*') f.wss.val = 0; else f.wss.val = strtoul(&pbeg[1], NULL, 10); } else if (pbeg[0] == '%') { f.wss.wc = OSF_WSS_MODULO; f.wss.val = strtoul(&pbeg[1], NULL, 10); } else if (isdigit(pbeg[0])) { f.wss.wc = OSF_WSS_PLAIN; f.wss.val = strtoul(&pbeg[0], NULL, 10); } pbeg = pend + 1; } pend = xt_osf_strchr(pbeg, OSFPDEL); if (pend) { *pend = '\0'; f.ttl = strtoul(pbeg, NULL, 10); pbeg = pend + 1; } pend = xt_osf_strchr(pbeg, OSFPDEL); if (pend) { *pend = '\0'; f.df = strtoul(pbeg, NULL, 10); pbeg = pend + 1; } pend = xt_osf_strchr(pbeg, OSFPDEL); if (pend) { *pend = '\0'; f.ss = strtoul(pbeg, NULL, 10); pbeg = pend + 1; } pend = xt_osf_strchr(pbeg, OSFPDEL); if (pend) { *pend = '\0'; cnt = snprintf(obuf, sizeof(obuf), "%s,", pbeg); pbeg = pend + 1; } pend = xt_osf_strchr(pbeg, OSFPDEL); if (pend) { *pend = '\0'; if (pbeg[0] == '@' || pbeg[0] == '*') cnt = snprintf(f.genre, sizeof(f.genre), "%s", pbeg + 1); else cnt = snprintf(f.genre, sizeof(f.genre), "%s", pbeg); pbeg = pend + 1; } pend = xt_osf_strchr(pbeg, OSFPDEL); if (pend) { *pend = '\0'; cnt = snprintf(f.version, sizeof(f.version), "%s", pbeg); pbeg = pend + 1; } pend = xt_osf_strchr(pbeg, OSFPDEL); if (pend) { *pend = '\0'; cnt = snprintf(f.subtype, sizeof(f.subtype), "%s", pbeg); pbeg = pend + 1; } xt_osf_parse_opt(f.opt, &f.opt_num, obuf, sizeof(obuf)); memset(buf, 0, sizeof(buf)); if (del) nfnl_fill_hdr(nfnlssh, nmh, 0, AF_UNSPEC, 0, OSF_MSG_REMOVE, NLM_F_REQUEST); else nfnl_fill_hdr(nfnlssh, nmh, 0, AF_UNSPEC, 0, OSF_MSG_ADD, NLM_F_REQUEST | NLM_F_CREATE); nfnl_addattr_l(nmh, sizeof(buf), OSF_ATTR_FINGER, &f, sizeof(struct xt_osf_user_finger)); return nfnl_talk(nfnlh, nmh, 0, 0, NULL, NULL, NULL); }
int get_src_for_route_to(const struct sockaddr * dst, void * src, size_t * src_len, int * index) { #if __linux__ int fd = -1; struct nlmsghdr *h; int status; struct { struct nlmsghdr n; struct rtmsg r; char buf[1024]; } req; struct sockaddr_nl nladdr; struct iovec iov = { .iov_base = (void*) &req.n, }; struct msghdr msg = { .msg_name = &nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = &iov, .msg_iovlen = 1, }; const struct sockaddr_in * dst4; const struct sockaddr_in6 * dst6; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_GETROUTE; req.r.rtm_family = dst->sa_family; req.r.rtm_table = 0; req.r.rtm_protocol = 0; req.r.rtm_scope = 0; req.r.rtm_type = 0; req.r.rtm_src_len = 0; req.r.rtm_dst_len = 0; req.r.rtm_tos = 0; { char dst_str[128]; sockaddr_to_string(dst, dst_str, sizeof(dst_str)); syslog(LOG_DEBUG, "get_src_for_route_to (%s)", dst_str); } /* add address */ if(dst->sa_family == AF_INET) { dst4 = (const struct sockaddr_in *)dst; nfnl_addattr_l(&req.n, sizeof(req), RTA_DST, &dst4->sin_addr, 4); req.r.rtm_dst_len = 32; } else { dst6 = (const struct sockaddr_in6 *)dst; nfnl_addattr_l(&req.n, sizeof(req), RTA_DST, &dst6->sin6_addr, 16); req.r.rtm_dst_len = 128; } fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (fd < 0) { syslog(LOG_ERR, "socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE) : %m"); return -1; } memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; req.n.nlmsg_seq = 1; iov.iov_len = req.n.nlmsg_len; status = sendmsg(fd, &msg, 0); if (status < 0) { syslog(LOG_ERR, "sendmsg(rtnetlink) : %m"); goto error; } memset(&req, 0, sizeof(req)); for(;;) { iov.iov_len = sizeof(req); status = recvmsg(fd, &msg, 0); if(status < 0) { if (errno == EINTR || errno == EAGAIN) continue; syslog(LOG_ERR, "recvmsg(rtnetlink) %m"); goto error; } if(status == 0) { syslog(LOG_ERR, "recvmsg(rtnetlink) EOF"); goto error; } for (h = (struct nlmsghdr*)&req.n; status >= (int)sizeof(*h); ) { int len = h->nlmsg_len; int l = len - sizeof(*h); if (l<0 || len>status) { if (msg.msg_flags & MSG_TRUNC) { syslog(LOG_ERR, "Truncated message"); } syslog(LOG_ERR, "malformed message: len=%d", len); goto error; } if(nladdr.nl_pid != 0 || h->nlmsg_seq != 1/*seq*/) { syslog(LOG_ERR, "wrong seq = %d\n", h->nlmsg_seq); /* Don't forget to skip that message. */ status -= NLMSG_ALIGN(len); h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); continue; } if(h->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); syslog(LOG_ERR, "NLMSG_ERROR %d : %s", err->error, strerror(-err->error)); goto error; } if(h->nlmsg_type == RTM_NEWROUTE) { struct rtattr * rta; int len = h->nlmsg_len; len -= NLMSG_LENGTH(sizeof(struct rtmsg)); for(rta = RTM_RTA(NLMSG_DATA((h))); RTA_OK(rta, len); rta = RTA_NEXT(rta,len)) { unsigned char * data = RTA_DATA(rta); if(rta->rta_type == RTA_PREFSRC) { if(src_len && src) { if(*src_len < RTA_PAYLOAD(rta)) { syslog(LOG_WARNING, "cannot copy src: %u<%lu", (unsigned)*src_len, (unsigned long)RTA_PAYLOAD(rta)); goto error; } *src_len = RTA_PAYLOAD(rta); memcpy(src, data, RTA_PAYLOAD(rta)); } } else if(rta->rta_type == RTA_OIF) { if(index) memcpy(index, data, sizeof(int)); } } close(fd); return 0; } status -= NLMSG_ALIGN(len); h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); } } syslog(LOG_WARNING, "get_src_for_route_to() : src not found"); error: if(fd >= 0) close(fd); return -1; #else /* __linux__ */ int found = 0; int s; int l, i; char * p; struct sockaddr * sa; struct { struct rt_msghdr m_rtm; char m_space[512]; } m_rtmsg; #define rtm m_rtmsg.m_rtm if(dst == NULL) return -1; #ifdef __APPLE__ if(dst->sa_family == AF_INET6) { syslog(LOG_ERR, "Sorry, get_src_for_route_to() is known to fail with IPV6 on OS X..."); return -1; } #endif s = socket(PF_ROUTE, SOCK_RAW, dst->sa_family); if(s < 0) { syslog(LOG_ERR, "socket(PF_ROUTE) failed : %m"); return -1; } memset(&rtm, 0, sizeof(rtm)); rtm.rtm_type = RTM_GET; rtm.rtm_flags = RTF_UP; rtm.rtm_version = RTM_VERSION; rtm.rtm_seq = 1; rtm.rtm_addrs = RTA_DST; /* destination address */ memcpy(m_rtmsg.m_space, dst, sizeof(struct sockaddr)); rtm.rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr); if(write(s, &m_rtmsg, rtm.rtm_msglen) < 0) { syslog(LOG_ERR, "write: %m"); close(s); return -1; } do { l = read(s, &m_rtmsg, sizeof(m_rtmsg)); if(l<0) { syslog(LOG_ERR, "read: %m"); close(s); return -1; } syslog(LOG_DEBUG, "read l=%d seq=%d pid=%d", l, rtm.rtm_seq, rtm.rtm_pid); } while(l > 0 && (rtm.rtm_pid != getpid() || rtm.rtm_seq != 1)); close(s); p = m_rtmsg.m_space; if(rtm.rtm_addrs) { for(i=1; i<0x8000; i <<= 1) { if(i & rtm.rtm_addrs) { char tmp[256] = { 0 }; sa = (struct sockaddr *)p; sockaddr_to_string(sa, tmp, sizeof(tmp)); syslog(LOG_DEBUG, "type=%d sa_len=%d sa_family=%d %s", i, SA_LEN(sa), sa->sa_family, tmp); if((i == RTA_DST || i == RTA_GATEWAY) && (src_len && src)) { size_t len = 0; void * paddr = NULL; if(sa->sa_family == AF_INET) { paddr = &((struct sockaddr_in *)sa)->sin_addr; len = sizeof(struct in_addr); } else if(sa->sa_family == AF_INET6) { paddr = &((struct sockaddr_in6 *)sa)->sin6_addr; len = sizeof(struct in6_addr); } if(paddr) { if(*src_len < len) { syslog(LOG_WARNING, "cannot copy src. %u<%u", (unsigned)*src_len, (unsigned)len); return -1; } memcpy(src, paddr, len); *src_len = len; found = 1; } } #ifdef AF_LINK if(sa->sa_family == AF_LINK) { struct sockaddr_dl * sdl = (struct sockaddr_dl *)sa; if(index) *index = sdl->sdl_index; } #endif p += SA_LEN(sa); } } } return found ? 0 : -1; #endif /* __linux__ */ }