Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at c9a28fa7b9ac19b676deefa0a171ce7df8755c08 206 lines 5.0 kB view raw
1/* 2 * dccp_probe - Observe the DCCP flow with kprobes. 3 * 4 * The idea for this came from Werner Almesberger's umlsim 5 * Copyright (C) 2004, Stephen Hemminger <shemminger@osdl.org> 6 * 7 * Modified for DCCP from Stephen Hemminger's code 8 * Copyright (C) 2006, Ian McDonald <ian.mcdonald@jandi.co.nz> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 23 */ 24 25#include <linux/kernel.h> 26#include <linux/kprobes.h> 27#include <linux/socket.h> 28#include <linux/dccp.h> 29#include <linux/proc_fs.h> 30#include <linux/module.h> 31#include <linux/kfifo.h> 32#include <linux/vmalloc.h> 33#include <net/net_namespace.h> 34 35#include "dccp.h" 36#include "ccid.h" 37#include "ccids/ccid3.h" 38 39static int port; 40 41static int bufsize = 64 * 1024; 42 43static const char procname[] = "dccpprobe"; 44 45struct { 46 struct kfifo *fifo; 47 spinlock_t lock; 48 wait_queue_head_t wait; 49 struct timeval tstart; 50} dccpw; 51 52static void printl(const char *fmt, ...) 53{ 54 va_list args; 55 int len; 56 struct timeval now; 57 char tbuf[256]; 58 59 va_start(args, fmt); 60 do_gettimeofday(&now); 61 62 now.tv_sec -= dccpw.tstart.tv_sec; 63 now.tv_usec -= dccpw.tstart.tv_usec; 64 if (now.tv_usec < 0) { 65 --now.tv_sec; 66 now.tv_usec += 1000000; 67 } 68 69 len = sprintf(tbuf, "%lu.%06lu ", 70 (unsigned long) now.tv_sec, 71 (unsigned long) now.tv_usec); 72 len += vscnprintf(tbuf+len, sizeof(tbuf)-len, fmt, args); 73 va_end(args); 74 75 kfifo_put(dccpw.fifo, tbuf, len); 76 wake_up(&dccpw.wait); 77} 78 79static int jdccp_sendmsg(struct kiocb *iocb, struct sock *sk, 80 struct msghdr *msg, size_t size) 81{ 82 const struct dccp_minisock *dmsk = dccp_msk(sk); 83 const struct inet_sock *inet = inet_sk(sk); 84 const struct ccid3_hc_tx_sock *hctx; 85 86 if (dmsk->dccpms_tx_ccid == DCCPC_CCID3) 87 hctx = ccid3_hc_tx_sk(sk); 88 else 89 hctx = NULL; 90 91 if (port == 0 || ntohs(inet->dport) == port || 92 ntohs(inet->sport) == port) { 93 if (hctx) 94 printl("%d.%d.%d.%d:%u %d.%d.%d.%d:%u %d %d %d %d %u " 95 "%llu %llu %d\n", 96 NIPQUAD(inet->saddr), ntohs(inet->sport), 97 NIPQUAD(inet->daddr), ntohs(inet->dport), size, 98 hctx->ccid3hctx_s, hctx->ccid3hctx_rtt, 99 hctx->ccid3hctx_p, hctx->ccid3hctx_x_calc, 100 hctx->ccid3hctx_x_recv >> 6, 101 hctx->ccid3hctx_x >> 6, hctx->ccid3hctx_t_ipi); 102 else 103 printl("%d.%d.%d.%d:%u %d.%d.%d.%d:%u %d\n", 104 NIPQUAD(inet->saddr), ntohs(inet->sport), 105 NIPQUAD(inet->daddr), ntohs(inet->dport), size); 106 } 107 108 jprobe_return(); 109 return 0; 110} 111 112static struct jprobe dccp_send_probe = { 113 .kp = { 114 .symbol_name = "dccp_sendmsg", 115 }, 116 .entry = jdccp_sendmsg, 117}; 118 119static int dccpprobe_open(struct inode *inode, struct file *file) 120{ 121 kfifo_reset(dccpw.fifo); 122 do_gettimeofday(&dccpw.tstart); 123 return 0; 124} 125 126static ssize_t dccpprobe_read(struct file *file, char __user *buf, 127 size_t len, loff_t *ppos) 128{ 129 int error = 0, cnt = 0; 130 unsigned char *tbuf; 131 132 if (!buf) 133 return -EINVAL; 134 135 if (len == 0) 136 return 0; 137 138 tbuf = vmalloc(len); 139 if (!tbuf) 140 return -ENOMEM; 141 142 error = wait_event_interruptible(dccpw.wait, 143 __kfifo_len(dccpw.fifo) != 0); 144 if (error) 145 goto out_free; 146 147 cnt = kfifo_get(dccpw.fifo, tbuf, len); 148 error = copy_to_user(buf, tbuf, cnt); 149 150out_free: 151 vfree(tbuf); 152 153 return error ? error : cnt; 154} 155 156static const struct file_operations dccpprobe_fops = { 157 .owner = THIS_MODULE, 158 .open = dccpprobe_open, 159 .read = dccpprobe_read, 160}; 161 162static __init int dccpprobe_init(void) 163{ 164 int ret = -ENOMEM; 165 166 init_waitqueue_head(&dccpw.wait); 167 spin_lock_init(&dccpw.lock); 168 dccpw.fifo = kfifo_alloc(bufsize, GFP_KERNEL, &dccpw.lock); 169 if (IS_ERR(dccpw.fifo)) 170 return PTR_ERR(dccpw.fifo); 171 172 if (!proc_net_fops_create(&init_net, procname, S_IRUSR, &dccpprobe_fops)) 173 goto err0; 174 175 ret = register_jprobe(&dccp_send_probe); 176 if (ret) 177 goto err1; 178 179 pr_info("DCCP watch registered (port=%d)\n", port); 180 return 0; 181err1: 182 proc_net_remove(&init_net, procname); 183err0: 184 kfifo_free(dccpw.fifo); 185 return ret; 186} 187module_init(dccpprobe_init); 188 189static __exit void dccpprobe_exit(void) 190{ 191 kfifo_free(dccpw.fifo); 192 proc_net_remove(&init_net, procname); 193 unregister_jprobe(&dccp_send_probe); 194 195} 196module_exit(dccpprobe_exit); 197 198MODULE_PARM_DESC(port, "Port to match (0=all)"); 199module_param(port, int, 0); 200 201MODULE_PARM_DESC(bufsize, "Log buffer size (default 64k)"); 202module_param(bufsize, int, 0); 203 204MODULE_AUTHOR("Ian McDonald <ian.mcdonald@jandi.co.nz>"); 205MODULE_DESCRIPTION("DCCP snooper"); 206MODULE_LICENSE("GPL");