diff options
Diffstat (limited to '')
-rw-r--r-- | iv/orodja/ldmitm/.gitignore | 1 | ||||
-rw-r--r-- | iv/orodja/ldmitm/Makefile | 17 | ||||
-rw-r--r-- | iv/orodja/ldmitm/tcp_times.c | 117 | ||||
-rw-r--r-- | iv/orodja/ldmitm/tcp_times.h | 27 | ||||
-rw-r--r-- | iv/orodja/ldmitm/tcp_times_example.c | 56 |
5 files changed, 218 insertions, 0 deletions
diff --git a/iv/orodja/ldmitm/.gitignore b/iv/orodja/ldmitm/.gitignore new file mode 100644 index 0000000..3ce51cd --- /dev/null +++ b/iv/orodja/ldmitm/.gitignore @@ -0,0 +1 @@ +tcp_times_example diff --git a/iv/orodja/ldmitm/Makefile b/iv/orodja/ldmitm/Makefile new file mode 100644 index 0000000..4010899 --- /dev/null +++ b/iv/orodja/ldmitm/Makefile @@ -0,0 +1,17 @@ +obj-m += tcp_times.o + +all: allmods tcp_times_example ldmitm.so + +%.so: %.c + cc -shared -fPIC -ldl $< -o $@ + +%: %.c + cc -g -Wall -Wextra -pedantic -Wformat -Wformat-security -o$@ $< + +allmods: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean + rm ldmitm.so tcp_times_example + +.PHONY: allmods clean diff --git a/iv/orodja/ldmitm/tcp_times.c b/iv/orodja/ldmitm/tcp_times.c new file mode 100644 index 0000000..0996857 --- /dev/null +++ b/iv/orodja/ldmitm/tcp_times.c @@ -0,0 +1,117 @@ +/* +Prevajanje: make +Namestitev v jedro: insmod tcp_times.ko +Uporaba v C: +#include <stdint.h> +#include "tcp_times.h" +int tcp_times = open("/proc/tcp_times", O_RDWR); +if (tcp_times == -1) { + perror("open tcp_times"); + break; +} +int tcpsock = accept(boundsocket, &address, &addrlen); +struct tcp_times tt = { + .fd = tcpsock +}; +if (ioctl(tcp_times, 0, &tt) == -1) { + perror("ioctl tcp_times"); + break; +} +// sedaj so polja v tt populirana +*/ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/uaccess.h> +#include <linux/fs.h> +#include <linux/proc_fs.h> +#include <linux/net.h> +#include <linux/tcp.h> +#include <linux/version.h> +#include "tcp_times.h" +#define MIN(a,b) (((a)<(b))?(a):(b)) +MODULE_AUTHOR("Anton Luka Šijanec <anton@sijanec.eu>"); +MODULE_DESCRIPTION("tcp last received tsval, rtt procfs ioctl driver"); +MODULE_LICENSE(""); +static struct proc_dir_entry * ent; +static long myioctl (struct file * filep, unsigned int cmd, unsigned long arg) { + switch(cmd) { + case 0: + struct tcp_times tt; + if (copy_from_user(&tt, (void *) arg, sizeof tt)) + return -EFAULT; + struct fd f = fdget(tt.fd); + if (!f.file) + return -EBADF; + struct socket * sock = sock_from_file(f.file); + if (!sock) { + fdput(f); + return -ENOTSOCK; + } + if (!(sock->type & SOCK_STREAM)) { + fdput(f); + return -ENOSTR; + } + if (!sock->sk) { + fdput(f); + return -EBADFD; + } + if (sock->sk->sk_protocol != IPPROTO_TCP) { + fdput(f); + return -ESOCKTNOSUPPORT; + } + struct tcp_sock * tp = tcp_sk(sock->sk); + tt.ts_recent_stamp = tp->rx_opt.ts_recent_stamp; + tt.ts_recent = tp->rx_opt.ts_recent; + tt.rcv_tsval = tp->rx_opt.rcv_tsval; + tt.rcv_tsecr = tp->rx_opt.rcv_tsecr; + tt.saw_tstamp = tp->rx_opt.saw_tstamp; + tt.tstamp_ok = tp->rx_opt.tstamp_ok; + tt.dsack = tp->rx_opt.dsack; + tt.wscale_ok = tp->rx_opt.wscale_ok; + tt.sack_ok = tp->rx_opt.sack_ok; + tt.smc_ok = tp->rx_opt.smc_ok; + tt.snd_wscale = tp->rx_opt.snd_wscale; + tt.rcv_wscale = tp->rx_opt.rcv_wscale; + tt.advmss = tp->advmss; + tt.rttvar_us = tp->rttvar_us; + tt.srtt_us = tp->srtt_us; + tt.rcv_rtt_est.rtt_us = tp->rcv_rtt_est.rtt_us; + tt.rcv_rtt_est.seq = tp->rcv_rtt_est.seq; + tt.rcv_rtt_est.time = tp->rcv_rtt_est.time; + tt.rtt_us = tp->rack.rtt_us; + tt.mdev_max_us = tp->mdev_max_us; + fdput(f); + if (copy_to_user((void *) arg, &tt, sizeof tt)) { + fdput(f); + return -EFAULT; + } + return 0; + default: + return -EINVAL; + } +} +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0) +static const struct file_operations ops = { + .owner = THIS_MODULE, + .unlocked_ioctl = myioctl, +}; +#else +static const struct proc_ops ops = { + .proc_ioctl = myioctl, +}; +#endif +static int __init custom_init (void) { + ent = proc_create("tcp_times", 0666, NULL, &ops); + if (!ent) { + printk(KERN_INFO "tcp_times failed to create procfs entry."); + return -EINVAL; + } + printk(KERN_INFO "tcp_times kernel module loaded."); + return 0; +} +static void __exit custom_exit (void) { + proc_remove(ent); + printk(KERN_INFO "tcp_times kernel module exiting ..."); +} +module_init(custom_init); +module_exit(custom_exit); diff --git a/iv/orodja/ldmitm/tcp_times.h b/iv/orodja/ldmitm/tcp_times.h new file mode 100644 index 0000000..3368c7b --- /dev/null +++ b/iv/orodja/ldmitm/tcp_times.h @@ -0,0 +1,27 @@ +#define TCP_TIMES_PRINTF_FORMAT "fd: %d, ts_recent_stamp: %d, ts_recent: %u, rcv_tsval: %u, rcv_tsecr: %u, saw_tstamp: %u, tstamp_ok: %u, dsack: %u, wscale_ok: %u, sack_ok: %u, snd_wscale: %u, rcv_wscale: %u, advmss: %u, rttvar_us: %u, srtt_us: %u, rcv_rtt_est.rtt_us: %u, rcv_rtt_est.seq: %u, rcv_rtt_est.time: %lu, rtt_us: %u, mdev_max_us: %u" +#define TCP_TIMES_PRINTF_VARIABLES(tt) tt fd, tt ts_recent_stamp, tt ts_recent, tt rcv_tsval, tt rcv_tsecr, tt saw_tstamp, tt tstamp_ok, tt dsack, tt wscale_ok, tt sack_ok, tt snd_wscale, tt rcv_wscale, tt advmss, tt rttvar_us, tt srtt_us, tt rcv_rtt_est.rtt_us, tt rcv_rtt_est.seq, tt rcv_rtt_est.time, tt rtt_us, tt mdev_max_us +struct tcp_times { // Polja so pobrana iz jedra. Glej https://elixir.bootlin.com/linux/v6.11-rc4/source/include/linux/tcp.h#L302 + int fd; + int ts_recent_stamp;/* Time we stored ts_recent (for aging) */ + uint32_t ts_recent; /* Time stamp to echo next */ + uint32_t rcv_tsval; /* Time stamp value */ + uint32_t rcv_tsecr; /* Time stamp echo reply */ + uint16_t saw_tstamp : 1, /* Saw TIMESTAMP on last packet */ + tstamp_ok : 1, /* TIMESTAMP seen on SYN packet */ + dsack : 1, /* D-SACK is scheduled */ + wscale_ok : 1, /* Wscale seen on SYN packet */ + sack_ok : 3, /* SACK seen on SYN packet */ + smc_ok : 1, /* SMC seen on SYN packet */ + snd_wscale : 4, /* Window scaling received from sender */ + rcv_wscale : 4; /* Window scaling to send to receiver */ + uint16_t advmss; /* Advertised MSS */ + uint32_t rttvar_us; /* smoothed mdev_max */ + uint32_t srtt_us; /* smoothed round trip time << 3 in usecs */ + struct { + uint32_t rtt_us; + uint32_t seq; + uint64_t time; + } rcv_rtt_est; + uint32_t rtt_us; /* Associated RTT */ + uint32_t mdev_max_us; /* maximal mdev for the last rtt period */ +}; // Ne vem, kaj veliko polj tu pomeni, vendar jih dodajam. Mogoče bodo uporabna. diff --git a/iv/orodja/ldmitm/tcp_times_example.c b/iv/orodja/ldmitm/tcp_times_example.c new file mode 100644 index 0000000..c98b29a --- /dev/null +++ b/iv/orodja/ldmitm/tcp_times_example.c @@ -0,0 +1,56 @@ +/* +Posluša na TCP vratih 6969, prejme eno povezavo, vsako sekundo nanjo izpiše LF in piše statistiko, dobljeno iz jedrnega modula tcp_times. +*/ +#include <stdint.h> +#include "tcp_times.h" +#include <stdio.h> +#include <stdlib.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <unistd.h> +#include <stdbool.h> +#include <sys/ioctl.h> +#include <fcntl.h> +int main (void) { + int tcp_socket = socket(AF_INET6, SOCK_STREAM, 0); + if (tcp_socket == -1) { + perror("socket"); + return 1; + } + struct sockaddr_in6 sa6 = { + .sin6_family = AF_INET6, + .sin6_port = htons(6969), + .sin6_addr = IN6ADDR_ANY_INIT, + }; + if (bind(tcp_socket, (struct sockaddr *) &sa6, sizeof sa6) == -1) { + perror("bind"); + return 1; + } + if (listen(tcp_socket, 1 /* only one client is handled*/) == -1) { + perror("listen"); + return 1; + } + int flow = accept(tcp_socket, NULL, NULL); + if (flow == -1) { + perror("accept"); + return 1; + } + int tcp_times = open("/proc/tcp_times", O_RDWR); + struct tcp_times tt = { + .fd = flow, + }; + char buf = '\n'; + while (true) { + if (ioctl(tcp_times, 0, &tt) == -1) { + perror("ioctl"); + return 1; + } + printf(TCP_TIMES_PRINTF_FORMAT "\n", TCP_TIMES_PRINTF_VARIABLES(tt.)); + if (send(flow, &buf, 1, MSG_NOSIGNAL) == -1) { + perror("write"); + return 1; + } + sleep(1); + } +} |