ipt_ULOG.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:9k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * netfilter module for userspace packet logging daemons
  3.  *
  4.  * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
  5.  *
  6.  * 2000/09/22 ulog-cprange feature added
  7.  * 2001/01/04 in-kernel queue as proposed by Sebastian Zander 
  8.  *  <zander@fokus.gmd.de>
  9.  * 2001/01/30 per-rule nlgroup conflicts with global queue. 
  10.  *            nlgroup now global (sysctl)
  11.  * 2001/04/19 ulog-queue reworked, now fixed buffer size specified at
  12.  *        module loadtime -HW
  13.  *
  14.  * Released under the terms of the GPL
  15.  *
  16.  * This module accepts two parameters: 
  17.  * 
  18.  * nlbufsiz:
  19.  *   The parameter specifies how big the buffer for each netlink multicast
  20.  * group is. e.g. If you say nlbufsiz=8192, up to eight kb of packets will
  21.  * get accumulated in the kernel until they are sent to userspace. It is
  22.  * NOT possible to allocate more than 128kB, and it is strongly discouraged,
  23.  * because atomically allocating 128kB inside the network rx softirq is not
  24.  * reliable. Please also keep in mind that this buffer size is allocated for
  25.  * each nlgroup you are using, so the total kernel memory usage increases
  26.  * by that factor.
  27.  *
  28.  * flushtimeout:
  29.  *   Specify, after how many clock ticks (intel: 100 per second) the queue
  30.  * should be flushed even if it is not full yet.
  31.  *
  32.  * ipt_ULOG.c,v 1.15 2002/01/18 21:33:19 laforge Exp
  33.  */
  34. #include <linux/module.h>
  35. #include <linux/version.h>
  36. #include <linux/config.h>
  37. #include <linux/spinlock.h>
  38. #include <linux/socket.h>
  39. #include <linux/skbuff.h>
  40. #include <linux/kernel.h>
  41. #include <linux/timer.h>
  42. #include <linux/netlink.h>
  43. #include <linux/netdevice.h>
  44. #include <linux/mm.h>
  45. #include <linux/socket.h>
  46. #include <linux/netfilter_ipv4/ip_tables.h>
  47. #include <linux/netfilter_ipv4/ipt_ULOG.h>
  48. #include <linux/netfilter_ipv4/lockhelp.h>
  49. #include <net/sock.h>
  50. MODULE_LICENSE("GPL");
  51. #define ULOG_NL_EVENT 111 /* Harald's favorite number */
  52. #define ULOG_MAXNLGROUPS 32 /* numer of nlgroups */
  53. #if 0
  54. #define DEBUGP(format, args...) printk(__FILE__ ":" __FUNCTION__ ":" 
  55.        format, ## args)
  56. #else
  57. #define DEBUGP(format, args...)
  58. #endif
  59. #define PRINTR(format, args...) do { if (net_ratelimit()) printk(format, ## args); } while (0);
  60. MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
  61. MODULE_DESCRIPTION("IP tables userspace logging module");
  62. static unsigned int nlbufsiz = 4096;
  63. MODULE_PARM(nlbufsiz, "i");
  64. MODULE_PARM_DESC(nlbufsiz, "netlink buffer size");
  65. static unsigned int flushtimeout = 10 * HZ;
  66. MODULE_PARM(flushtimeout, "i");
  67. MODULE_PARM_DESC(flushtimeout, "buffer flush timeout");
  68. /* global data structures */
  69. typedef struct {
  70. unsigned int qlen; /* number of nlmsgs' in the skb */
  71. struct nlmsghdr *lastnlh; /* netlink header of last msg in skb */
  72. struct sk_buff *skb; /* the pre-allocated skb */
  73. struct timer_list timer; /* the timer function */
  74. } ulog_buff_t;
  75. static ulog_buff_t ulog_buffers[ULOG_MAXNLGROUPS]; /* array of buffers */
  76. static struct sock *nflognl; /* our socket */
  77. static size_t qlen; /* current length of multipart-nlmsg */
  78. DECLARE_LOCK(ulog_lock); /* spinlock */
  79. /* send one ulog_buff_t to userspace */
  80. static void ulog_send(unsigned int nlgroup)
  81. {
  82. ulog_buff_t *ub = &ulog_buffers[nlgroup];
  83. if (timer_pending(&ub->timer)) {
  84. DEBUGP("ipt_ULOG: ulog_send: timer was pending, deletingn");
  85. del_timer(&ub->timer);
  86. }
  87. /* last nlmsg needs NLMSG_DONE */
  88. if (ub->qlen > 1)
  89. ub->lastnlh->nlmsg_type = NLMSG_DONE;
  90. NETLINK_CB(ub->skb).dst_groups = nlgroup;
  91. DEBUGP("ipt_ULOG: throwing %d packets to netlink mask %un",
  92. ub->qlen, nlgroup);
  93. netlink_broadcast(nflognl, ub->skb, 0, nlgroup, GFP_ATOMIC);
  94. ub->qlen = 0;
  95. ub->skb = NULL;
  96. ub->lastnlh = NULL;
  97. }
  98. /* timer function to flush queue in ULOG_FLUSH_INTERVAL time */
  99. static void ulog_timer(unsigned long data)
  100. {
  101. DEBUGP("ipt_ULOG: timer function called, calling ulog_sendn");
  102. /* lock to protect against somebody modifying our structure
  103.  * from ipt_ulog_target at the same time */
  104. LOCK_BH(&ulog_lock);
  105. ulog_send(data);
  106. UNLOCK_BH(&ulog_lock);
  107. }
  108. static void nflog_rcv(struct sock *sk, int len)
  109. {
  110. printk("ipt_ULOG:nflog_rcv() did receive netlink message ?!?n");
  111. }
  112. struct sk_buff *ulog_alloc_skb(unsigned int size)
  113. {
  114. struct sk_buff *skb;
  115. /* alloc skb which should be big enough for a whole
  116.  * multipart message. WARNING: has to be <= 131000
  117.  * due to slab allocator restrictions */
  118. skb = alloc_skb(nlbufsiz, GFP_ATOMIC);
  119. if (!skb) {
  120. PRINTR("ipt_ULOG: can't alloc whole buffer %ub!n",
  121. nlbufsiz);
  122. /* try to allocate only as much as we need for 
  123.  * current packet */
  124. skb = alloc_skb(size, GFP_ATOMIC);
  125. if (!skb)
  126. PRINTR("ipt_ULOG: can't even allocate %ubn", size);
  127. }
  128. return skb;
  129. }
  130. static unsigned int ipt_ulog_target(struct sk_buff **pskb,
  131.     unsigned int hooknum,
  132.     const struct net_device *in,
  133.     const struct net_device *out,
  134.     const void *targinfo, void *userinfo)
  135. {
  136. ulog_buff_t *ub;
  137. ulog_packet_msg_t *pm;
  138. size_t size, copy_len;
  139. struct nlmsghdr *nlh;
  140. struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
  141. /* calculate the size of the skb needed */
  142. if ((loginfo->copy_range == 0) ||
  143.     (loginfo->copy_range > (*pskb)->len)) {
  144. copy_len = (*pskb)->len;
  145. } else {
  146. copy_len = loginfo->copy_range;
  147. }
  148. size = NLMSG_SPACE(sizeof(*pm) + copy_len);
  149. ub = &ulog_buffers[loginfo->nl_group];
  150. LOCK_BH(&ulog_lock);
  151. if (!ub->skb) {
  152. if (!(ub->skb = ulog_alloc_skb(size)))
  153. goto alloc_failure;
  154. } else if (ub->qlen >= loginfo->qthreshold ||
  155.    size > skb_tailroom(ub->skb)) {
  156. /* either the queue len is too high or we don't have 
  157.  * enough room in nlskb left. send it to userspace. */
  158. ulog_send(loginfo->nl_group);
  159. if (!(ub->skb = ulog_alloc_skb(size)))
  160. goto alloc_failure;
  161. }
  162. DEBUGP("ipt_ULOG: qlen %d, qthreshold %dn", ub->qlen, 
  163. loginfo->qthreshold);
  164. /* NLMSG_PUT contains a hidden goto nlmsg_failure !!! */
  165. nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, ULOG_NL_EVENT, 
  166. size - sizeof(*nlh));
  167. ub->qlen++;
  168. pm = NLMSG_DATA(nlh);
  169. /* copy hook, prefix, timestamp, payload, etc. */
  170. pm->data_len = copy_len;
  171. pm->timestamp_sec = (*pskb)->stamp.tv_sec;
  172. pm->timestamp_usec = (*pskb)->stamp.tv_usec;
  173. pm->mark = (*pskb)->nfmark;
  174. pm->hook = hooknum;
  175. if (loginfo->prefix[0] != '')
  176. strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix));
  177. else
  178. *(pm->prefix) = '';
  179. if (in && in->hard_header_len > 0
  180.     && (*pskb)->mac.raw != (void *) (*pskb)->nh.iph
  181.     && in->hard_header_len <= ULOG_MAC_LEN) {
  182. memcpy(pm->mac, (*pskb)->mac.raw, in->hard_header_len);
  183. pm->mac_len = in->hard_header_len;
  184. }
  185. if (in)
  186. strncpy(pm->indev_name, in->name, sizeof(pm->indev_name));
  187. else
  188. pm->indev_name[0] = '';
  189. if (out)
  190. strncpy(pm->outdev_name, out->name, sizeof(pm->outdev_name));
  191. else
  192. pm->outdev_name[0] = '';
  193. if (copy_len)
  194. memcpy(pm->payload, (*pskb)->data, copy_len);
  195. /* check if we are building multi-part messages */
  196. if (ub->qlen > 1) {
  197. ub->lastnlh->nlmsg_flags |= NLM_F_MULTI;
  198. }
  199. /* if threshold is reached, send message to userspace */
  200. if (qlen >= loginfo->qthreshold) {
  201. if (loginfo->qthreshold > 1)
  202. nlh->nlmsg_type = NLMSG_DONE;
  203. }
  204. ub->lastnlh = nlh;
  205. /* if timer isn't already running, start it */
  206. if (!timer_pending(&ub->timer)) {
  207. ub->timer.expires = jiffies + flushtimeout;
  208. add_timer(&ub->timer);
  209. }
  210. UNLOCK_BH(&ulog_lock);
  211. return IPT_CONTINUE;
  212. nlmsg_failure:
  213. PRINTR("ipt_ULOG: error during NLMSG_PUTn");
  214. alloc_failure:
  215. PRINTR("ipt_ULOG: Error building netlink messagen");
  216. UNLOCK_BH(&ulog_lock);
  217. return IPT_CONTINUE;
  218. }
  219. static int ipt_ulog_checkentry(const char *tablename,
  220.        const struct ipt_entry *e,
  221.        void *targinfo,
  222.        unsigned int targinfosize,
  223.        unsigned int hookmask)
  224. {
  225. struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
  226. if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ulog_info))) {
  227. DEBUGP("ipt_ULOG: targinfosize %u != 0n", targinfosize);
  228. return 0;
  229. }
  230. if (loginfo->prefix[sizeof(loginfo->prefix) - 1] != '') {
  231. DEBUGP("ipt_ULOG: prefix term %in",
  232.        loginfo->prefix[sizeof(loginfo->prefix) - 1]);
  233. return 0;
  234. }
  235. if (loginfo->qthreshold > ULOG_MAX_QLEN) {
  236. DEBUGP("ipt_ULOG: queue threshold %i > MAX_QLENn",
  237. loginfo->qthreshold);
  238. return 0;
  239. }
  240. return 1;
  241. }
  242. static struct ipt_target ipt_ulog_reg =
  243.     { {NULL, NULL}, "ULOG", ipt_ulog_target, ipt_ulog_checkentry, NULL,
  244. THIS_MODULE
  245. };
  246. static int __init init(void)
  247. {
  248. int i;
  249. DEBUGP("ipt_ULOG: init modulen");
  250. if (nlbufsiz >= 128*1024) {
  251. printk("Netlink buffer has to be <= 128kBn");
  252. return -EINVAL;
  253. }
  254. /* initialize ulog_buffers */
  255. for (i = 0; i < ULOG_MAXNLGROUPS; i++) {
  256. memset(&ulog_buffers[i], 0, sizeof(ulog_buff_t));
  257. init_timer(&ulog_buffers[i].timer);
  258. ulog_buffers[i].timer.function = ulog_timer;
  259. ulog_buffers[i].timer.data = i;
  260. }
  261. nflognl = netlink_kernel_create(NETLINK_NFLOG, nflog_rcv);
  262. if (!nflognl)
  263. return -ENOMEM;
  264. if (ipt_register_target(&ipt_ulog_reg) != 0) {
  265. sock_release(nflognl->socket);
  266. return -EINVAL;
  267. }
  268. return 0;
  269. }
  270. static void __exit fini(void)
  271. {
  272. DEBUGP("ipt_ULOG: cleanup_modulen");
  273. ipt_unregister_target(&ipt_ulog_reg);
  274. sock_release(nflognl->socket);
  275. }
  276. module_init(init);
  277. module_exit(fini);