static struct sk_buff *ulog_alloc_skb(unsigned int size) { struct sk_buff *skb; unsigned int n; /* alloc skb which should be big enough for a whole * multipart message. WARNING: has to be <= 131000 * due to slab allocator restrictions */ n = max(size, nlbufsiz); skb = alloc_skb(n, GFP_ATOMIC); if (!skb) { PRINTR("ipt_ULOG: can't alloc whole buffer %ub!\n", n); if (n > size) { /* try to allocate only as much as we need for * current packet */ skb = alloc_skb(size, GFP_ATOMIC); if (!skb) PRINTR("ipt_ULOG: can't even allocate %ub\n", size); } } return skb; }
static struct sk_buff * nfulnl_alloc_skb(unsigned int inst_size, unsigned int pkt_size) { struct sk_buff *skb; unsigned int n; /* alloc skb which should be big enough for a whole multipart * message. WARNING: has to be <= 128k due to slab restrictions */ n = max(inst_size, pkt_size); skb = alloc_skb(n, GFP_ATOMIC); if (!skb) { PRINTR("nfnetlink_log: can't alloc whole buffer (%u bytes)\n", inst_size); if (n > pkt_size) { /* try to allocate only as much as we need for current * packet */ skb = alloc_skb(pkt_size, GFP_ATOMIC); if (!skb) PRINTR("nfnetlink_log: can't even alloc %u " "bytes\n", pkt_size); } } return skb; }
static struct sk_buff *ulog_alloc_skb(unsigned int size) { struct sk_buff *skb; unsigned int n; n = max(size, nlbufsiz); skb = alloc_skb(n, GFP_ATOMIC); if (!skb) { PRINTR(KERN_ERR "ebt_ulog: can't alloc whole buffer " "of size %ub!\n", n); if (n > size) { /* try to allocate only as much as we need for * current packet */ skb = alloc_skb(size, GFP_ATOMIC); if (!skb) PRINTR(KERN_ERR "ebt_ulog: can't even allocate " "buffer of size %ub\n", size); } } return skb; }
/* This is an inline function, we don't really care about a long * list of arguments */ static inline int __build_packet_message(struct nfnl_log_net *log, struct nfulnl_instance *inst, const struct sk_buff *skb, unsigned int data_len, u_int8_t pf, unsigned int hooknum, const struct net_device *indev, const struct net_device *outdev, const char *prefix, unsigned int plen, const struct nfnl_ct_hook *nfnl_ct, struct nf_conn *ct, enum ip_conntrack_info ctinfo) { struct nfulnl_msg_packet_hdr pmsg; struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; sk_buff_data_t old_tail = inst->skb->tail; struct sock *sk; const unsigned char *hwhdrp; nlh = nlmsg_put(inst->skb, 0, 0, nfnl_msg_type(NFNL_SUBSYS_ULOG, NFULNL_MSG_PACKET), sizeof(struct nfgenmsg), 0); if (!nlh) return -1; nfmsg = nlmsg_data(nlh); nfmsg->nfgen_family = pf; nfmsg->version = NFNETLINK_V0; nfmsg->res_id = htons(inst->group_num); memset(&pmsg, 0, sizeof(pmsg)); pmsg.hw_protocol = skb->protocol; pmsg.hook = hooknum; if (nla_put(inst->skb, NFULA_PACKET_HDR, sizeof(pmsg), &pmsg)) goto nla_put_failure; if (prefix && nla_put(inst->skb, NFULA_PREFIX, plen, prefix)) goto nla_put_failure; if (indev) { #if !IS_ENABLED(CONFIG_BRIDGE_NETFILTER) if (nla_put_be32(inst->skb, NFULA_IFINDEX_INDEV, htonl(indev->ifindex))) goto nla_put_failure; #else if (pf == PF_BRIDGE) { /* Case 1: outdev is physical input device, we need to * look for bridge group (when called from * netfilter_bridge) */ if (nla_put_be32(inst->skb, NFULA_IFINDEX_PHYSINDEV, htonl(indev->ifindex)) || /* this is the bridge group "brX" */ /* rcu_read_lock()ed by nf_hook_thresh or * nf_log_packet. */ nla_put_be32(inst->skb, NFULA_IFINDEX_INDEV, htonl(br_port_get_rcu(indev)->br->dev->ifindex))) goto nla_put_failure; } else { struct net_device *physindev; /* Case 2: indev is bridge group, we need to look for * physical device (when called from ipv4) */ if (nla_put_be32(inst->skb, NFULA_IFINDEX_INDEV, htonl(indev->ifindex))) goto nla_put_failure; physindev = nf_bridge_get_physindev(skb); if (physindev && nla_put_be32(inst->skb, NFULA_IFINDEX_PHYSINDEV, htonl(physindev->ifindex))) goto nla_put_failure; } #endif } if (outdev) { #if !IS_ENABLED(CONFIG_BRIDGE_NETFILTER) if (nla_put_be32(inst->skb, NFULA_IFINDEX_OUTDEV, htonl(outdev->ifindex))) goto nla_put_failure; #else if (pf == PF_BRIDGE) { /* Case 1: outdev is physical output device, we need to * look for bridge group (when called from * netfilter_bridge) */ if (nla_put_be32(inst->skb, NFULA_IFINDEX_PHYSOUTDEV, htonl(outdev->ifindex)) || /* this is the bridge group "brX" */ /* rcu_read_lock()ed by nf_hook_thresh or * nf_log_packet. */ nla_put_be32(inst->skb, NFULA_IFINDEX_OUTDEV, htonl(br_port_get_rcu(outdev)->br->dev->ifindex))) goto nla_put_failure; } else { struct net_device *physoutdev; /* Case 2: indev is a bridge group, we need to look * for physical device (when called from ipv4) */ if (nla_put_be32(inst->skb, NFULA_IFINDEX_OUTDEV, htonl(outdev->ifindex))) goto nla_put_failure; physoutdev = nf_bridge_get_physoutdev(skb); if (physoutdev && nla_put_be32(inst->skb, NFULA_IFINDEX_PHYSOUTDEV, htonl(physoutdev->ifindex))) goto nla_put_failure; } #endif } if (skb->mark && nla_put_be32(inst->skb, NFULA_MARK, htonl(skb->mark))) goto nla_put_failure; if (indev && skb->dev && skb->mac_header != skb->network_header) { struct nfulnl_msg_packet_hw phw; int len; memset(&phw, 0, sizeof(phw)); len = dev_parse_header(skb, phw.hw_addr); if (len > 0) { phw.hw_addrlen = htons(len); if (nla_put(inst->skb, NFULA_HWADDR, sizeof(phw), &phw)) goto nla_put_failure; } } if (indev && skb_mac_header_was_set(skb)) { if (nla_put_be16(inst->skb, NFULA_HWTYPE, htons(skb->dev->type)) || nla_put_be16(inst->skb, NFULA_HWLEN, htons(skb->dev->hard_header_len))) goto nla_put_failure; hwhdrp = skb_mac_header(skb); if (skb->dev->type == ARPHRD_SIT) hwhdrp -= ETH_HLEN; if (hwhdrp >= skb->head && nla_put(inst->skb, NFULA_HWHEADER, skb->dev->hard_header_len, hwhdrp)) goto nla_put_failure; } if (skb->tstamp) { struct nfulnl_msg_packet_timestamp ts; struct timespec64 kts = ktime_to_timespec64(skb->tstamp); ts.sec = cpu_to_be64(kts.tv_sec); ts.usec = cpu_to_be64(kts.tv_nsec / NSEC_PER_USEC); if (nla_put(inst->skb, NFULA_TIMESTAMP, sizeof(ts), &ts)) goto nla_put_failure; } /* UID */ sk = skb->sk; if (sk && sk_fullsock(sk)) { read_lock_bh(&sk->sk_callback_lock); if (sk->sk_socket && sk->sk_socket->file) { struct file *file = sk->sk_socket->file; const struct cred *cred = file->f_cred; struct user_namespace *user_ns = inst->peer_user_ns; __be32 uid = htonl(from_kuid_munged(user_ns, cred->fsuid)); __be32 gid = htonl(from_kgid_munged(user_ns, cred->fsgid)); read_unlock_bh(&sk->sk_callback_lock); if (nla_put_be32(inst->skb, NFULA_UID, uid) || nla_put_be32(inst->skb, NFULA_GID, gid)) goto nla_put_failure; } else read_unlock_bh(&sk->sk_callback_lock); } /* local sequence number */ if ((inst->flags & NFULNL_CFG_F_SEQ) && nla_put_be32(inst->skb, NFULA_SEQ, htonl(inst->seq++))) goto nla_put_failure; /* global sequence number */ if ((inst->flags & NFULNL_CFG_F_SEQ_GLOBAL) && nla_put_be32(inst->skb, NFULA_SEQ_GLOBAL, htonl(atomic_inc_return(&log->global_seq)))) goto nla_put_failure; if (ct && nfnl_ct->build(inst->skb, ct, ctinfo, NFULA_CT, NFULA_CT_INFO) < 0) goto nla_put_failure; if (data_len) { struct nlattr *nla; int size = nla_attr_size(data_len); if (skb_tailroom(inst->skb) < nla_total_size(data_len)) goto nla_put_failure; nla = skb_put(inst->skb, nla_total_size(data_len)); nla->nla_type = NFULA_PAYLOAD; nla->nla_len = size; if (skb_copy_bits(skb, 0, nla_data(nla), data_len)) BUG(); } nlh->nlmsg_len = inst->skb->tail - old_tail; return 0; nla_put_failure: PRINTR(KERN_ERR "nfnetlink_log: error creating log nlmsg\n"); return -1; }
/* This is an inline function, we don't really care about a long * list of arguments */ static inline int __build_packet_message(struct nfulnl_instance *inst, const struct sk_buff *skb, unsigned int data_len, u_int8_t pf, unsigned int hooknum, const struct net_device *indev, const struct net_device *outdev, const char *prefix, unsigned int plen) { struct nfulnl_msg_packet_hdr pmsg; struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; sk_buff_data_t old_tail = inst->skb->tail; nlh = NLMSG_PUT(inst->skb, 0, 0, NFNL_SUBSYS_ULOG << 8 | NFULNL_MSG_PACKET, sizeof(struct nfgenmsg)); nfmsg = NLMSG_DATA(nlh); nfmsg->nfgen_family = pf; nfmsg->version = NFNETLINK_V0; nfmsg->res_id = htons(inst->group_num); pmsg.hw_protocol = skb->protocol; pmsg.hook = hooknum; NLA_PUT(inst->skb, NFULA_PACKET_HDR, sizeof(pmsg), &pmsg); if (prefix) NLA_PUT(inst->skb, NFULA_PREFIX, plen, prefix); if (indev) { #ifndef CONFIG_BRIDGE_NETFILTER NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_INDEV, htonl(indev->ifindex)); #else if (pf == PF_BRIDGE) { /* Case 1: outdev is physical input device, we need to * look for bridge group (when called from * netfilter_bridge) */ NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_PHYSINDEV, htonl(indev->ifindex)); /* this is the bridge group "brX" */ /* rcu_read_lock()ed by nf_hook_slow or nf_log_packet */ NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_INDEV, htonl(br_port_get_rcu(indev)->br->dev->ifindex)); } else { /* Case 2: indev is bridge group, we need to look for * physical device (when called from ipv4) */ NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_INDEV, htonl(indev->ifindex)); if (skb->nf_bridge && skb->nf_bridge->physindev) NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_PHYSINDEV, htonl(skb->nf_bridge->physindev->ifindex)); } #endif } if (outdev) { #ifndef CONFIG_BRIDGE_NETFILTER NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_OUTDEV, htonl(outdev->ifindex)); #else if (pf == PF_BRIDGE) { /* Case 1: outdev is physical output device, we need to * look for bridge group (when called from * netfilter_bridge) */ NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_PHYSOUTDEV, htonl(outdev->ifindex)); /* this is the bridge group "brX" */ /* rcu_read_lock()ed by nf_hook_slow or nf_log_packet */ NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_OUTDEV, htonl(br_port_get_rcu(outdev)->br->dev->ifindex)); } else { /* Case 2: indev is a bridge group, we need to look * for physical device (when called from ipv4) */ NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_OUTDEV, htonl(outdev->ifindex)); if (skb->nf_bridge && skb->nf_bridge->physoutdev) NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_PHYSOUTDEV, htonl(skb->nf_bridge->physoutdev->ifindex)); } #endif } if (skb->mark) NLA_PUT_BE32(inst->skb, NFULA_MARK, htonl(skb->mark)); if (indev && skb->dev && skb->mac_header != skb->network_header) { struct nfulnl_msg_packet_hw phw; int len = dev_parse_header(skb, phw.hw_addr); if (len > 0) { phw.hw_addrlen = htons(len); NLA_PUT(inst->skb, NFULA_HWADDR, sizeof(phw), &phw); } } if (indev && skb_mac_header_was_set(skb)) { NLA_PUT_BE16(inst->skb, NFULA_HWTYPE, htons(skb->dev->type)); NLA_PUT_BE16(inst->skb, NFULA_HWLEN, htons(skb->dev->hard_header_len)); NLA_PUT(inst->skb, NFULA_HWHEADER, skb->dev->hard_header_len, skb_mac_header(skb)); } if (skb->tstamp.tv64) { struct nfulnl_msg_packet_timestamp ts; struct timeval tv = ktime_to_timeval(skb->tstamp); ts.sec = cpu_to_be64(tv.tv_sec); ts.usec = cpu_to_be64(tv.tv_usec); NLA_PUT(inst->skb, NFULA_TIMESTAMP, sizeof(ts), &ts); } /* UID */ if (skb->sk) { read_lock_bh(&skb->sk->sk_callback_lock); if (skb->sk->sk_socket && skb->sk->sk_socket->file) { struct file *file = skb->sk->sk_socket->file; __be32 uid = htonl(file->f_cred->fsuid); __be32 gid = htonl(file->f_cred->fsgid); /* need to unlock here since NLA_PUT may goto */ read_unlock_bh(&skb->sk->sk_callback_lock); NLA_PUT_BE32(inst->skb, NFULA_UID, uid); NLA_PUT_BE32(inst->skb, NFULA_GID, gid); } else read_unlock_bh(&skb->sk->sk_callback_lock); } /* local sequence number */ if (inst->flags & NFULNL_CFG_F_SEQ) NLA_PUT_BE32(inst->skb, NFULA_SEQ, htonl(inst->seq++)); /* global sequence number */ if (inst->flags & NFULNL_CFG_F_SEQ_GLOBAL) NLA_PUT_BE32(inst->skb, NFULA_SEQ_GLOBAL, htonl(atomic_inc_return(&global_seq))); if (data_len) { struct nlattr *nla; int size = nla_attr_size(data_len); if (skb_tailroom(inst->skb) < nla_total_size(data_len)) { printk(KERN_WARNING "nfnetlink_log: no tailroom!\n"); goto nlmsg_failure; } nla = (struct nlattr *)skb_put(inst->skb, nla_total_size(data_len)); nla->nla_type = NFULA_PAYLOAD; nla->nla_len = size; if (skb_copy_bits(skb, 0, nla_data(nla), data_len)) BUG(); } nlh->nlmsg_len = inst->skb->tail - old_tail; return 0; nlmsg_failure: nla_put_failure: PRINTR(KERN_ERR "nfnetlink_log: error creating log nlmsg\n"); return -1; }
static unsigned int ipt_ulog_target(struct sk_buff **pskb, unsigned int hooknum, const struct net_device *in, const struct net_device *out, const void *targinfo, void *userinfo) { ulog_buff_t *ub; ulog_packet_msg_t *pm; size_t size, copy_len; struct nlmsghdr *nlh; struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo; /* calculate the size of the skb needed */ if ((loginfo->copy_range == 0) || (loginfo->copy_range > (*pskb)->len)) { copy_len = (*pskb)->len; } else { copy_len = loginfo->copy_range; } size = NLMSG_SPACE(sizeof(*pm) + copy_len); ub = &ulog_buffers[loginfo->nl_group]; LOCK_BH(&ulog_lock); if (!ub->skb) { if (!(ub->skb = ulog_alloc_skb(size))) goto alloc_failure; } else if (ub->qlen >= loginfo->qthreshold || size > skb_tailroom(ub->skb)) { /* either the queue len is too high or we don't have * enough room in nlskb left. send it to userspace. */ ulog_send(loginfo->nl_group); if (!(ub->skb = ulog_alloc_skb(size))) goto alloc_failure; } DEBUGP("ipt_ULOG: qlen %d, qthreshold %d\n", ub->qlen, loginfo->qthreshold); /* NLMSG_PUT contains a hidden goto nlmsg_failure !!! */ nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, ULOG_NL_EVENT, size - sizeof(*nlh)); ub->qlen++; pm = NLMSG_DATA(nlh); /* copy hook, prefix, timestamp, payload, etc. */ pm->data_len = copy_len; pm->timestamp_sec = (*pskb)->stamp.tv_sec; pm->timestamp_usec = (*pskb)->stamp.tv_usec; pm->mark = (*pskb)->nfmark; pm->hook = hooknum; if (loginfo->prefix[0] != '\0') strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix)); else *(pm->prefix) = '\0'; if (in && in->hard_header_len > 0 && (*pskb)->mac.raw != (void *) (*pskb)->nh.iph && in->hard_header_len <= ULOG_MAC_LEN) { memcpy(pm->mac, (*pskb)->mac.raw, in->hard_header_len); pm->mac_len = in->hard_header_len; } if (in) strncpy(pm->indev_name, in->name, sizeof(pm->indev_name)); else pm->indev_name[0] = '\0'; if (out) strncpy(pm->outdev_name, out->name, sizeof(pm->outdev_name)); else pm->outdev_name[0] = '\0'; if (copy_len) memcpy(pm->payload, (*pskb)->data, copy_len); /* check if we are building multi-part messages */ if (ub->qlen > 1) { ub->lastnlh->nlmsg_flags |= NLM_F_MULTI; } /* if threshold is reached, send message to userspace */ if (qlen >= loginfo->qthreshold) { if (loginfo->qthreshold > 1) nlh->nlmsg_type = NLMSG_DONE; } ub->lastnlh = nlh; /* if timer isn't already running, start it */ if (!timer_pending(&ub->timer)) { ub->timer.expires = jiffies + flushtimeout; add_timer(&ub->timer); } UNLOCK_BH(&ulog_lock); return IPT_CONTINUE; nlmsg_failure: PRINTR("ipt_ULOG: error during NLMSG_PUT\n"); alloc_failure: PRINTR("ipt_ULOG: Error building netlink message\n"); UNLOCK_BH(&ulog_lock); return IPT_CONTINUE; }
static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, const struct ebt_ulog_info *uloginfo, const char *prefix) { ebt_ulog_packet_msg_t *pm; size_t size, copy_len; struct nlmsghdr *nlh; unsigned int group = uloginfo->nlgroup; ebt_ulog_buff_t *ub = &ulog_buffers[group]; spinlock_t *lock = &ub->lock; ktime_t kt; if ((uloginfo->cprange == 0) || (uloginfo->cprange > skb->len + ETH_HLEN)) copy_len = skb->len + ETH_HLEN; else copy_len = uloginfo->cprange; size = NLMSG_SPACE(sizeof(*pm) + copy_len); if (size > nlbufsiz) { PRINTR("ebt_ulog: Size %Zd needed, but nlbufsiz=%d\n", size, nlbufsiz); return; } spin_lock_bh(lock); if (!ub->skb) { if (!(ub->skb = ulog_alloc_skb(size))) goto alloc_failure; } else if (size > skb_tailroom(ub->skb)) { ulog_send(group); if (!(ub->skb = ulog_alloc_skb(size))) goto alloc_failure; } nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, 0, size - NLMSG_ALIGN(sizeof(*nlh))); ub->qlen++; pm = NLMSG_DATA(nlh); /* Fill in the ulog data */ pm->version = EBT_ULOG_VERSION; kt = ktime_get_real(); pm->stamp = ktime_to_timeval(kt); if (ub->qlen == 1) ub->skb->tstamp = kt; pm->data_len = copy_len; pm->mark = skb->mark; pm->hook = hooknr; if (uloginfo->prefix != NULL) strcpy(pm->prefix, uloginfo->prefix); else *(pm->prefix) = '\0'; if (in) { strcpy(pm->physindev, in->name); /* If in isn't a bridge, then physindev==indev */ if (in->br_port) strcpy(pm->indev, in->br_port->br->dev->name); else strcpy(pm->indev, in->name); } else pm->indev[0] = pm->physindev[0] = '\0'; if (out) { /* If out exists, then out is a bridge port */ strcpy(pm->physoutdev, out->name); strcpy(pm->outdev, out->br_port->br->dev->name); } else pm->outdev[0] = pm->physoutdev[0] = '\0'; if (skb_copy_bits(skb, -ETH_HLEN, pm->data, copy_len) < 0) BUG(); if (ub->qlen > 1) ub->lastnlh->nlmsg_flags |= NLM_F_MULTI; ub->lastnlh = nlh; if (ub->qlen >= uloginfo->qthreshold) ulog_send(group); else if (!timer_pending(&ub->timer)) { ub->timer.expires = jiffies + flushtimeout * HZ / 100; add_timer(&ub->timer); } unlock: spin_unlock_bh(lock); return; nlmsg_failure: printk(KERN_CRIT "ebt_ulog: error during NLMSG_PUT. This should " "not happen, please report to author.\n"); goto unlock; alloc_failure: goto unlock; }
static void ipt_ulog_packet(unsigned int hooknum, const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, const struct ipt_ulog_info *loginfo, const char *prefix) { ulog_buff_t *ub; ulog_packet_msg_t *pm; size_t size, copy_len; struct nlmsghdr *nlh; /* ffs == find first bit set, necessary because userspace * is already shifting groupnumber, but we need unshifted. * ffs() returns [1..32], we need [0..31] */ unsigned int groupnum = ffs(loginfo->nl_group) - 1; /* calculate the size of the skb needed */ if ((loginfo->copy_range == 0) || (loginfo->copy_range > skb->len)) { copy_len = skb->len; } else { copy_len = loginfo->copy_range; } size = NLMSG_SPACE(sizeof(*pm) + copy_len); ub = &ulog_buffers[groupnum]; spin_lock_bh(&ulog_lock); if (!ub->skb) { if (!(ub->skb = ulog_alloc_skb(size))) goto alloc_failure; } else if (ub->qlen >= loginfo->qthreshold || size > skb_tailroom(ub->skb)) { /* either the queue len is too high or we don't have * enough room in nlskb left. send it to userspace. */ ulog_send(groupnum); if (!(ub->skb = ulog_alloc_skb(size))) goto alloc_failure; } DEBUGP("ipt_ULOG: qlen %d, qthreshold %d\n", ub->qlen, loginfo->qthreshold); /* NLMSG_PUT contains a hidden goto nlmsg_failure !!! */ nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, ULOG_NL_EVENT, sizeof(*pm)+copy_len); ub->qlen++; pm = NLMSG_DATA(nlh); /* We might not have a timestamp, get one */ if (skb->tstamp.off_sec == 0) __net_timestamp((struct sk_buff *)skb); /* copy hook, prefix, timestamp, payload, etc. */ pm->data_len = copy_len; pm->timestamp_sec = skb->tstamp.off_sec; pm->timestamp_usec = skb->tstamp.off_usec; pm->mark = skb->nfmark; pm->hook = hooknum; if (prefix != NULL) strncpy(pm->prefix, prefix, sizeof(pm->prefix)); else if (loginfo->prefix[0] != '\0') strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix)); else *(pm->prefix) = '\0'; if (in && in->hard_header_len > 0 && skb->mac.raw != (void *) skb->nh.iph && in->hard_header_len <= ULOG_MAC_LEN) { memcpy(pm->mac, skb->mac.raw, in->hard_header_len); pm->mac_len = in->hard_header_len; } else pm->mac_len = 0; if (in) strncpy(pm->indev_name, in->name, sizeof(pm->indev_name)); else pm->indev_name[0] = '\0'; if (out) strncpy(pm->outdev_name, out->name, sizeof(pm->outdev_name)); else pm->outdev_name[0] = '\0'; /* copy_len <= skb->len, so can't fail. */ if (skb_copy_bits(skb, 0, pm->payload, copy_len) < 0) BUG(); /* check if we are building multi-part messages */ if (ub->qlen > 1) { ub->lastnlh->nlmsg_flags |= NLM_F_MULTI; } ub->lastnlh = nlh; /* if timer isn't already running, start it */ if (!timer_pending(&ub->timer)) { ub->timer.expires = jiffies + flushtimeout * HZ / 100; add_timer(&ub->timer); } /* if threshold is reached, send message to userspace */ if (ub->qlen >= loginfo->qthreshold) { if (loginfo->qthreshold > 1) nlh->nlmsg_type = NLMSG_DONE; ulog_send(groupnum); } spin_unlock_bh(&ulog_lock); return; nlmsg_failure: PRINTR("ipt_ULOG: error during NLMSG_PUT\n"); alloc_failure: PRINTR("ipt_ULOG: Error building netlink message\n"); spin_unlock_bh(&ulog_lock); }
/* log handler for internal netfilter logging api */ static void nfulnl_log_packet(unsigned int pf, unsigned int hooknum, const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, const struct nf_loginfo *li_user, const char *prefix) { unsigned int size, data_len; struct nfulnl_instance *inst; const struct nf_loginfo *li; unsigned int qthreshold; unsigned int nlbufsiz; if (li_user && li_user->type == NF_LOG_TYPE_ULOG) li = li_user; else li = &default_loginfo; inst = instance_lookup_get(li->u.ulog.group); if (!inst) inst = instance_lookup_get(0); if (!inst) { PRINTR("nfnetlink_log: trying to log packet, " "but no instance for group %u\n", li->u.ulog.group); return; } /* all macros expand to constant values at compile time */ /* FIXME: do we want to make the size calculation conditional based on * what is actually present? way more branches and checks, but more * memory efficient... */ size = NLMSG_SPACE(sizeof(struct nfgenmsg)) + NFA_SPACE(sizeof(struct nfulnl_msg_packet_hdr)) + NFA_SPACE(sizeof(u_int32_t)) /* ifindex */ + NFA_SPACE(sizeof(u_int32_t)) /* ifindex */ #ifdef CONFIG_BRIDGE_NETFILTER + NFA_SPACE(sizeof(u_int32_t)) /* ifindex */ + NFA_SPACE(sizeof(u_int32_t)) /* ifindex */ #endif + NFA_SPACE(sizeof(u_int32_t)) /* mark */ + NFA_SPACE(sizeof(u_int32_t)) /* uid */ + NFA_SPACE(NFULNL_PREFIXLEN) /* prefix */ + NFA_SPACE(sizeof(struct nfulnl_msg_packet_hw)) + NFA_SPACE(sizeof(struct nfulnl_msg_packet_timestamp)); UDEBUG("initial size=%u\n", size); spin_lock_bh(&inst->lock); if (inst->flags & NFULNL_CFG_F_SEQ) size += NFA_SPACE(sizeof(u_int32_t)); if (inst->flags & NFULNL_CFG_F_SEQ_GLOBAL) size += NFA_SPACE(sizeof(u_int32_t)); qthreshold = inst->qthreshold; /* per-rule qthreshold overrides per-instance */ if (qthreshold > li->u.ulog.qthreshold) qthreshold = li->u.ulog.qthreshold; switch (inst->copy_mode) { case NFULNL_COPY_META: case NFULNL_COPY_NONE: data_len = 0; break; case NFULNL_COPY_PACKET: if (inst->copy_range == 0 || inst->copy_range > skb->len) data_len = skb->len; else data_len = inst->copy_range; size += NFA_SPACE(data_len); UDEBUG("copy_packet, therefore size now %u\n", size); break; default: spin_unlock_bh(&inst->lock); instance_put(inst); return; } if (size > inst->nlbufsiz) nlbufsiz = size; else nlbufsiz = inst->nlbufsiz; if (!inst->skb) { if (!(inst->skb = nfulnl_alloc_skb(nlbufsiz, size))) { UDEBUG("error in nfulnl_alloc_skb(%u, %u)\n", inst->nlbufsiz, size); goto alloc_failure; } } else if (inst->qlen >= qthreshold || size > skb_tailroom(inst->skb)) { /* either the queue len is too high or we don't have * enough room in the skb left. flush to userspace. */ UDEBUG("flushing old skb\n"); __nfulnl_send(inst); if (!(inst->skb = nfulnl_alloc_skb(nlbufsiz, size))) { UDEBUG("error in nfulnl_alloc_skb(%u, %u)\n", inst->nlbufsiz, size); goto alloc_failure; } } UDEBUG("qlen %d, qthreshold %d\n", inst->qlen, qthreshold); inst->qlen++; __build_packet_message(inst, skb, data_len, pf, hooknum, in, out, li, prefix); /* timer_pending always called within inst->lock, so there * is no chance of a race here */ if (!timer_pending(&inst->timer)) { instance_get(inst); inst->timer.expires = jiffies + (inst->flushtimeout*HZ/100); add_timer(&inst->timer); } spin_unlock_bh(&inst->lock); return; alloc_failure: spin_unlock_bh(&inst->lock); instance_put(inst); UDEBUG("error allocating skb\n"); /* FIXME: statistics */ }
/* This is an inline function, we don't really care about a long * list of arguments */ static inline int __build_packet_message(struct nfulnl_instance *inst, const struct sk_buff *skb, unsigned int data_len, unsigned int pf, unsigned int hooknum, const struct net_device *indev, const struct net_device *outdev, const struct nf_loginfo *li, const char *prefix) { unsigned char *old_tail; struct nfulnl_msg_packet_hdr pmsg; struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; u_int32_t tmp_uint; UDEBUG("entered\n"); old_tail = inst->skb->tail; nlh = NLMSG_PUT(inst->skb, 0, 0, NFNL_SUBSYS_ULOG << 8 | NFULNL_MSG_PACKET, sizeof(struct nfgenmsg)); nfmsg = NLMSG_DATA(nlh); nfmsg->nfgen_family = pf; nfmsg->version = NFNETLINK_V0; nfmsg->res_id = htons(inst->group_num); pmsg.hw_protocol = htons(skb->protocol); pmsg.hook = hooknum; NFA_PUT(inst->skb, NFULA_PACKET_HDR, sizeof(pmsg), &pmsg); if (prefix) { int slen = strlen(prefix); if (slen > NFULNL_PREFIXLEN) slen = NFULNL_PREFIXLEN; NFA_PUT(inst->skb, NFULA_PREFIX, slen, prefix); } if (indev) { tmp_uint = htonl(indev->ifindex); #ifndef CONFIG_BRIDGE_NETFILTER NFA_PUT(inst->skb, NFULA_IFINDEX_INDEV, sizeof(tmp_uint), &tmp_uint); #else if (pf == PF_BRIDGE) { /* Case 1: outdev is physical input device, we need to * look for bridge group (when called from * netfilter_bridge) */ NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSINDEV, sizeof(tmp_uint), &tmp_uint); /* this is the bridge group "brX" */ tmp_uint = htonl(indev->br_port->br->dev->ifindex); NFA_PUT(inst->skb, NFULA_IFINDEX_INDEV, sizeof(tmp_uint), &tmp_uint); } else { /* Case 2: indev is bridge group, we need to look for * physical device (when called from ipv4) */ NFA_PUT(inst->skb, NFULA_IFINDEX_INDEV, sizeof(tmp_uint), &tmp_uint); if (skb->nf_bridge && skb->nf_bridge->physindev) { tmp_uint = htonl(skb->nf_bridge->physindev->ifindex); NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSINDEV, sizeof(tmp_uint), &tmp_uint); } } #endif } if (outdev) { tmp_uint = htonl(outdev->ifindex); #ifndef CONFIG_BRIDGE_NETFILTER NFA_PUT(inst->skb, NFULA_IFINDEX_OUTDEV, sizeof(tmp_uint), &tmp_uint); #else if (pf == PF_BRIDGE) { /* Case 1: outdev is physical output device, we need to * look for bridge group (when called from * netfilter_bridge) */ NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSOUTDEV, sizeof(tmp_uint), &tmp_uint); /* this is the bridge group "brX" */ tmp_uint = htonl(outdev->br_port->br->dev->ifindex); NFA_PUT(inst->skb, NFULA_IFINDEX_OUTDEV, sizeof(tmp_uint), &tmp_uint); } else { /* Case 2: indev is a bridge group, we need to look * for physical device (when called from ipv4) */ NFA_PUT(inst->skb, NFULA_IFINDEX_OUTDEV, sizeof(tmp_uint), &tmp_uint); if (skb->nf_bridge) { tmp_uint = htonl(skb->nf_bridge->physoutdev->ifindex); NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSOUTDEV, sizeof(tmp_uint), &tmp_uint); } } #endif } if (skb->nfmark) { tmp_uint = htonl(skb->nfmark); NFA_PUT(inst->skb, NFULA_MARK, sizeof(tmp_uint), &tmp_uint); } if (indev && skb->dev && skb->dev->hard_header_parse) { struct nfulnl_msg_packet_hw phw; phw.hw_addrlen = skb->dev->hard_header_parse((struct sk_buff *)skb, phw.hw_addr); phw.hw_addrlen = htons(phw.hw_addrlen); NFA_PUT(inst->skb, NFULA_HWADDR, sizeof(phw), &phw); } if (skb->tstamp.off_sec) { struct nfulnl_msg_packet_timestamp ts; ts.sec = cpu_to_be64(skb->tstamp.off_sec); ts.usec = cpu_to_be64(skb->tstamp.off_usec); NFA_PUT(inst->skb, NFULA_TIMESTAMP, sizeof(ts), &ts); } /* UID */ if (skb->sk) { read_lock_bh(&skb->sk->sk_callback_lock); if (skb->sk->sk_socket && skb->sk->sk_socket->file) { u_int32_t uid = htonl(skb->sk->sk_socket->file->f_uid); /* need to unlock here since NFA_PUT may goto */ read_unlock_bh(&skb->sk->sk_callback_lock); NFA_PUT(inst->skb, NFULA_UID, sizeof(uid), &uid); } else read_unlock_bh(&skb->sk->sk_callback_lock); } /* local sequence number */ if (inst->flags & NFULNL_CFG_F_SEQ) { tmp_uint = htonl(inst->seq++); NFA_PUT(inst->skb, NFULA_SEQ, sizeof(tmp_uint), &tmp_uint); } /* global sequence number */ if (inst->flags & NFULNL_CFG_F_SEQ_GLOBAL) { tmp_uint = atomic_inc_return(&global_seq); NFA_PUT(inst->skb, NFULA_SEQ_GLOBAL, sizeof(tmp_uint), &tmp_uint); } if (data_len) { struct nfattr *nfa; int size = NFA_LENGTH(data_len); if (skb_tailroom(inst->skb) < (int)NFA_SPACE(data_len)) { printk(KERN_WARNING "nfnetlink_log: no tailroom!\n"); goto nlmsg_failure; } nfa = (struct nfattr *)skb_put(inst->skb, NFA_ALIGN(size)); nfa->nfa_type = NFULA_PAYLOAD; nfa->nfa_len = size; if (skb_copy_bits(skb, 0, NFA_DATA(nfa), data_len)) BUG(); } nlh->nlmsg_len = inst->skb->tail - old_tail; return 0; nlmsg_failure: UDEBUG("nlmsg_failure\n"); nfattr_failure: PRINTR(KERN_ERR "nfnetlink_log: error creating log nlmsg\n"); return -1; }
void IntegrateRationalFunction(node_type *root, char var, char newvar, int trace) { RatFun A, h, content; Coefficient R = {special}, rat_part = {rational}, solution = {special}; Coefficient *Qit = NULL, *Sit = NULL; Coefficient Qit2 = {special}, Sit2 = {special}; Integral integral; unsigned i; init_ratfun(&A); init_ratfun(&h); init_ratfun(&content); init_bigrat(&rat_part.u.rat); init_integral(&integral); if (root->type != ratfun_type) { printf("Error! IntegrateRationalFunction" "requires a rational function.\n"); return; } copy_ratfun(&integral.integrand, root->u.ratfun); integral.var = var; integral.newvar = newvar; if (ratfun_zero(integral.integrand)) { goto print; } /* make numerator and denominator primitive */ coef_content(&content.num, root->u.ratfun.num, var); exact_div_coefficients(&root->u.ratfun.num, root->u.ratfun.num, content.num); coef_content(&content.den, root->u.ratfun.den, var); exact_div_coefficients(&root->u.ratfun.den, root->u.ratfun.den, content.den); if (trace) { printf("Computing rational part of integral using " "Hermite reduction...\n"); WAIT; } HermiteReduce(&integral.rational_part, &h, root->u.ratfun, var, trace); /* put contents back on */ /* PRINTR(content); */ mul_ratfuns(&integral.rational_part, integral.rational_part, content); mul_ratfuns(&h, h, content); /* PRINTR(h); */ if (trace) { printf("Found rational part:\t\t"); print_ratfun(integral.rational_part); printf("\n"); printf("\nHermite reduction leaves:\t"); print_ratfun(h); printf("\n"); WAIT; printf("Remove polynomial part...\n"); WAIT; } polydiv_coefficients(&integral.poly_part, &R, h.num, h.den); if (trace) { printf("Polynomial part:\t\t"); print_coefficient(integral.poly_part); printf("\n"); } coef_integrate(&integral.poly_part, integral.poly_part, var); if (trace) { printf("Integrate it:\t\t\t"); print_coefficient(integral.poly_part); printf("\n"); WAIT; printf("Left over:\t\t\t"); print_coefficient(R); printf("/"); print_coefficient(h.den); printf("\n"); } if (!coef_zero(R) && coef_deg(h.den, var) > coef_deg(R, var)) { if (trace) { printf("\nComputing logarithmic part using " "Lazard-Rioboo-Trager algorithm...\n"); WAIT; } IntRationalLogPart(&integral.Qi, &integral.Si, R, h.den, var, newvar, trace); /* make Qi and Si primitive */ for (i = 0; i < integral.Qi.size; ++i) { Qit = ca_get2(&integral.Qi, i); Sit = ca_get2(&integral.Si, i); rat_part.u.rat = coef_rat_part(*Qit); mul_coefficients(Qit, *Qit, rat_part); free_bigrat(&rat_part.u.rat); /* rat_part.u.rat = coef_rat_part(*Sit); */ /* mul_coefficients(Sit, *Sit, rat_part); */ /* free_bigrat(&rat_part.u.rat); */ coef_pp(Qit, *Qit, newvar); /* coef_pp(Sit, *Sit, var); */ } if (trace) { printf("Found logarithmic part.\n"); printf("%d sum(s) over roots:\t\t", integral.Qi.size); if (integral.Qi.size > 0) { for (i = 0; i < integral.Qi.size; ++i) { printf("sum(%c | ", integral.newvar); print_coefficient(ca_get(&integral.Qi, i)); printf(" = 0) %c*ln(", integral.newvar); print_coefficient(ca_get(&integral.Si, i)); printf(")"); if (i < integral.Qi.size-1) { printf(" + "); } } } printf("\n"); WAIT; printf("Solve the linear univariate Qis to get explicit sums...\n"); } /* solve linear univariate Qis */ for (i = 0; i < integral.Qi.size; ++i) { if (coef_deg(ca_get(&integral.Qi, i), newvar) != 1 || !poly_univar(ca_get(&integral.Qi, i).u.poly)) { continue; } solve_linear_poly(&solution, ca_get(&integral.Qi, i).u.poly); subst_var_coef(ca_get2(&integral.Si, i), solution, newvar); /* move to solved arrays */ ca_push_back(&integral.QiS, solution); ca_push_back(&integral.SiS, ca_get(&integral.Si, i)); /* remove from normal arrays */ Qit2 = ca_remove(&integral.Qi, i); Sit2 = ca_remove(&integral.Si, i); free_coefficient(&Qit2); free_coefficient(&Sit2); --i; } /* make SiS primitive */ for (i = 0; i < integral.SiS.size; ++i) { Sit = ca_get2(&integral.SiS, i); rat_part.u.rat = coef_rat_part(*Sit); mul_coefficients(Sit, *Sit, rat_part); free_bigrat(&rat_part.u.rat); coef_pp(Sit, *Sit, var); } if (trace) { printf("Found %d explicit sum(s):\t", integral.QiS.size); if (integral.QiS.size > 0) { for (i = 0; i < integral.QiS.size; ++i) { if (!coef_one(ca_get(&integral.QiS, i))) { print_coefficient(ca_get(&integral.QiS, i)); printf("*ln("); } else { printf("ln("); } print_coefficient(ca_get(&integral.SiS, i)); printf(")"); if (i < integral.QiS.size-1) { printf(" + "); } } } printf("\n"); WAIT; } } else if (coef_deg(h.den, var) == 0) { /* this is actually just a poly over a constant, * so integrate it trivially */ coef_integrate(&R, R, var); /* move this to the numerator of h */ free_coefficient(&h.num); h.num = R; R.type = special; /* add h to the rational part of integral */ add_ratfuns(&integral.rational_part, integral.rational_part, h); } else { /* this shouldn't happen */ printf("Error! Invalid ratfun following Hermite reduction!\n"); PRINTR(h); printf("\n"); PRINTC(R); printf("\n"); } print: if (trace) { printf("\nFinal answer:\n"); } print_integral(integral); printf("\nLaTeX format:\n"); print_integral_LaTeX(integral); free_ratfun(&A); free_ratfun(&h); free_ratfun(&content); free_coefficient(&R); free_integral(&integral); }