├── dist ├── lbm_rtp_proxy.conf ├── dkms.conf.in └── lbm_rtp_proxy.spec ├── .gitignore ├── src ├── rewrite.h ├── command.h ├── config.h ├── checksum.h ├── procfs.h ├── debug.h ├── module.c ├── mangle.h ├── config.c ├── table.h ├── module.h ├── debug.c ├── command.c ├── mangle.c ├── table.c ├── procfs.c ├── rtp_packet.h ├── rewrite.c ├── checksum.c └── rtcp_packet.h ├── tests ├── Makefile ├── config_test.c ├── tests.h ├── rtp_packet_test.c └── table_test.c ├── Makefile ├── README.md └── COPYING /dist/lbm_rtp_proxy.conf: -------------------------------------------------------------------------------- 1 | lbm_rtp_proxy 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.cmd 2 | *.ko 3 | *.mod 4 | *.mod.c 5 | *.o 6 | 7 | Module.symvers 8 | modules.order 9 | tests/*_test 10 | -------------------------------------------------------------------------------- /dist/dkms.conf.in: -------------------------------------------------------------------------------- 1 | PACKAGE_NAME="lbm_rtp_proxy" 2 | PACKAGE_VERSION="__VSN__" 3 | MAKE[0]="make -C ${kernel_source_dir} M=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build LBM_RTP_PROXY_VERSION=\"__VSN__\"" 4 | CLEAN="make -C ${kernel_source_dir} M=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build clean" 5 | AUTOINSTALL=yes 6 | BUILT_MODULE_NAME[0]="lbm_rtp_proxy" 7 | DEST_MODULE_LOCATION[0]=/extra 8 | -------------------------------------------------------------------------------- /src/rewrite.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Lindenbaum GmbH 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef _REWRITE_H_ 19 | #define _REWRITE_H_ 20 | 21 | #include "config.h" 22 | #include "table.h" 23 | #include "mangle.h" 24 | 25 | #endif // _REWRITE_H_ 26 | -------------------------------------------------------------------------------- /src/command.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Lindenbaum GmbH 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef _COMMAND_H_ 19 | #define _COMMAND_H_ 20 | 21 | #include "procfs.h" 22 | 23 | #include "config.h" 24 | #include "table.h" 25 | 26 | #endif // _COMMAND_H_ 27 | -------------------------------------------------------------------------------- /src/config.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Lindenbaum GmbH 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef _CONFIG_H_ 19 | #define _CONFIG_H_ 20 | 21 | #include "module.h" 22 | 23 | struct config { 24 | __be32 int_proxy_addr; 25 | __be32 ext_proxy_addr; 26 | uint8_t smoothing; 27 | uint8_t loopback; 28 | }; 29 | 30 | void config_init(void); 31 | 32 | void config_get(struct config *cfg); 33 | 34 | void config_set(struct config *cfg); 35 | 36 | void config_clr(void); 37 | 38 | #endif // _CONFIG_H_ 39 | -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2015 Lindenbaum GmbH 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | CFLAGS := -DTESTS 19 | CFLAGS += -DMODULE_NAME='"dummy"' 20 | 21 | .PHONY: all 22 | all: table_test config_test rtp_packet_test 23 | @for i in $^ ; do echo -e "\033[1;33mrunning $$i\033[0m" ; ./$$i ; done 24 | 25 | .PHONY: clean 26 | clean: 27 | @rm -f *_test 28 | 29 | table_test: table_test.c ../src/table.c ../src/config.c 30 | 31 | config_test: config_test.c ../src/config.c 32 | 33 | rtp_packet_test: rtp_packet_test.c 34 | -------------------------------------------------------------------------------- /src/checksum.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Lindenbaum GmbH 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef _CHECKSUM_H_ 19 | #define _CHECKSUM_H_ 20 | 21 | #ifdef __KERNEL__ 22 | #include 23 | #endif 24 | 25 | #include "module.h" 26 | #include "debug.h" 27 | 28 | void handle_incoming_checksums(struct sk_buff *skb, struct iphdr *ip_header, struct udphdr *udp_header); 29 | 30 | void handle_outgoing_checksums(struct sk_buff *skb, struct iphdr *ip_header, struct udphdr *udp_header); 31 | 32 | #endif // _CHECKSUM_H_ 33 | -------------------------------------------------------------------------------- /src/procfs.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Lindenbaum GmbH 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef _PROCFS_H_ 19 | #define _PROCFS_H_ 20 | 21 | #ifdef __KERNEL__ 22 | #include 23 | #include 24 | #include 25 | #include 26 | #endif 27 | 28 | #include "module.h" 29 | 30 | //API 31 | 32 | // create proc file 33 | void proc_file_create(void); 34 | 35 | // remove proc file 36 | void proc_file_remove(void); 37 | 38 | // must be defined elsewhere 39 | extern bool handle_command(const char *command); 40 | 41 | #endif // _PROCFS_H_ 42 | -------------------------------------------------------------------------------- /tests/config_test.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Lindenbaum GmbH 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "tests.h" 19 | 20 | #include "../src/config.h" 21 | 22 | static void new_config_is_all_zero_test(void) { 23 | struct config cfg; 24 | config_get(&cfg); 25 | bool is_non_zero = cfg.int_proxy_addr || cfg.ext_proxy_addr; 26 | if(is_non_zero) { 27 | printf("BUG %hu %hu\n", 28 | cfg.int_proxy_addr, cfg.ext_proxy_addr); 29 | exit(-1); 30 | } 31 | } 32 | 33 | int main(int argc, char **argv) { 34 | config_init(); 35 | 36 | new_config_is_all_zero_test(); 37 | 38 | printf(KGRN"SUCCESS"KNRM"\n"); 39 | exit(0); 40 | } 41 | -------------------------------------------------------------------------------- /src/debug.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Lindenbaum GmbH 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef _DEBUG_H_ 19 | #define _DEBUG_H_ 20 | 21 | #ifdef DEBUG 22 | 23 | #ifdef __KERNEL__ 24 | #include 25 | #include 26 | #endif 27 | 28 | #include "module.h" 29 | 30 | const char *ip_summed_toString(__u8 ip_summed); 31 | 32 | void debug_print_tuple(const char *msg, 33 | __be32 src_addr, __be16 src_port, 34 | __be32 dst_addr, __be16 dst_port); 35 | 36 | void debug_print_skb(const char *msg, struct sk_buff *skb, struct iphdr *ip_header, struct udphdr *udp_header); 37 | 38 | #define debug_printk(fmt, ...) printk(fmt, ##__VA_ARGS__) 39 | 40 | #else 41 | 42 | #define ip_summed_toString(ip_summed) (void *)0 43 | #define debug_print_tuple(msg, src_addr, src_port, dst_addr, dst_port) do {} while(0) 44 | #define debug_print_skb(msg, skb, ip_header, udp_header) do {} while(0) 45 | #define debug_printk(fmt, ...) do {} while(0) 46 | 47 | #endif 48 | 49 | #endif // _DEBUG_H_ 50 | -------------------------------------------------------------------------------- /src/module.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Lindenbaum GmbH 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "config.h" 19 | #include "table.h" 20 | #include "procfs.h" 21 | #include "mangle.h" 22 | 23 | #ifndef VERSION 24 | #define VERSION "V1.0" 25 | #endif 26 | 27 | #ifdef DEBUG 28 | # ifdef TESTS 29 | # define MODE "DEBUG TESTS" 30 | # else 31 | # define MODE "DEBUG" 32 | # endif 33 | #else 34 | # ifdef TESTS 35 | # define MODE "PRODUCTION TESTS" 36 | # else 37 | # define MODE "PRODUCTION" 38 | # endif 39 | #endif 40 | 41 | #ifndef TESTS 42 | static 43 | #endif 44 | int __init rtp_proxy_init(void) { 45 | printk(BANNER "init "VERSION" "MODE" [build date "__DATE__" "__TIME__"]\n"); 46 | config_init(); 47 | table_init(); 48 | proc_file_create(); 49 | register_nf_hooks(); 50 | return 0; 51 | } 52 | 53 | #ifndef TESTS 54 | static 55 | #endif 56 | void __exit rtp_proxy_exit(void) { 57 | unregister_nf_hooks(); 58 | proc_file_remove(); 59 | printk(BANNER "exit\n"); 60 | } 61 | 62 | MODULE_LICENSE("GPL"); 63 | MODULE_AUTHOR("Lindenbaum GmbH"); 64 | MODULE_DESCRIPTION("Lindenbaum RTP proxy/relay kernel module"); 65 | module_init(rtp_proxy_init); 66 | module_exit(rtp_proxy_exit); 67 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2015 Lindenbaum GmbH 3 | # Copyright (C) 2021 vier GmbH 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | KSRC ?= /lib/modules/$(shell uname -r)/build 20 | KBUILD := $(KSRC) 21 | 22 | ifeq ($(LBM_RTP_PROXY_VERSION),) 23 | LBM_RTP_PROXY_VERSION := 1.0.4-1 24 | endif 25 | 26 | ifdef DEBUG 27 | EXTRA_CFLAGS += -DDEBUG 28 | LBM_RTP_PROXY_VERSION += $(LBM_RTP_PROXY_VERSION)-debug 29 | endif 30 | EXTRA_CFLAGS += -DMODULE_NAME="\"lbm_rtp_proxy\"" 31 | EXTRA_CFLAGS += -DVERSION="\"$(LBM_RTP_PROXY_VERSION)\"" 32 | EXTRA_CFLAGS += -Wall -Wno-date-time 33 | 34 | obj-m += lbm_rtp_proxy.o 35 | lbm_rtp_proxy-objs := src/module.o \ 36 | src/config.o \ 37 | src/table.o \ 38 | src/procfs.o \ 39 | src/mangle.o \ 40 | src/checksum.o \ 41 | src/debug.o \ 42 | src/command.o \ 43 | src/rewrite.o 44 | 45 | .PHONY: all 46 | all: 47 | $(MAKE) -C $(KSRC) M=$(shell pwd) O=$(KSRC) modules 48 | 49 | .PHONY: test 50 | test: 51 | $(MAKE) -C tests all 52 | 53 | .PHONY: clean 54 | clean: 55 | $(MAKE) -C tests clean || true 56 | $(MAKE) -C $(KSRC) M=$(shell pwd) clean || true 57 | -------------------------------------------------------------------------------- /src/mangle.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Lindenbaum GmbH 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef _MANGLE_H_ 19 | #define _MANGLE_H_ 20 | 21 | #ifdef __KERNEL__ 22 | #include 23 | #endif 24 | 25 | #include "module.h" 26 | #include "debug.h" 27 | 28 | #include "config.h" 29 | #include "table.h" 30 | #include "checksum.h" 31 | 32 | // simplified nf_hookfn 33 | typedef unsigned int mangle_hook_fn(struct iphdr *ip_header, 34 | struct udphdr *udp_header, 35 | struct table_entry *ent, 36 | struct routing *rt); 37 | 38 | // simplified nf_hook_ops 39 | struct mangle_hook { 40 | int hooknum; // same as nf_hook_ops hooknum 41 | const char *name; // if non-NULL, interpret as UDP packet (and log hook name in DEBUG mode) 42 | mangle_hook_fn *fn; // if also non-NULL possibly mangle UDP packet 43 | int priority; // same as nf_hook_ops priority 44 | }; 45 | 46 | // API 47 | void register_nf_hooks(void); 48 | 49 | void unregister_nf_hooks(void); 50 | 51 | // must be defined elsewhere 52 | extern int get_mangle_hooks(struct mangle_hook **mangle_hooks); 53 | 54 | #endif // _MANGLE_H_ 55 | -------------------------------------------------------------------------------- /src/config.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Lindenbaum GmbH 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "config.h" 19 | 20 | static spinlock_t config_lock; 21 | static struct config config; 22 | 23 | #ifdef DEBUG 24 | static void config_print(struct config *cfg) { 25 | uint8_t int_proxy_ip[4] = htoal(ntohl(cfg->int_proxy_addr)); 26 | uint8_t ext_proxy_ip[4] = htoal(ntohl(cfg->ext_proxy_addr)); 27 | uint8_t smoothing = cfg->smoothing; 28 | uint8_t loopback = cfg->loopback; 29 | printk(BANNER "config:" " int_proxy_addr: "IP_FMT " ext_proxy_addr: "IP_FMT" smoothing: "U8_FMT" loopback: "U8_FMT"\n", 30 | int_proxy_ip[0], int_proxy_ip[1], int_proxy_ip[2], int_proxy_ip[3], 31 | ext_proxy_ip[0], ext_proxy_ip[1], ext_proxy_ip[2], ext_proxy_ip[3], 32 | smoothing, loopback); 33 | } 34 | #else 35 | #define config_print(x) do {} while(0) 36 | #endif 37 | 38 | void config_init(void) { 39 | spin_lock_init(&config_lock); 40 | config_clr(); 41 | } 42 | 43 | void config_set(struct config *cfg) { 44 | spin_lock_bh(&config_lock); 45 | config = *cfg; 46 | spin_unlock_bh(&config_lock); 47 | 48 | config_print(cfg); 49 | } 50 | 51 | void config_get(struct config *cfg) { 52 | spin_lock_bh(&config_lock); 53 | *cfg = config; 54 | spin_unlock_bh(&config_lock); 55 | } 56 | 57 | void config_clr(void) { 58 | empty_struct(config, cfg); 59 | cfg.smoothing = 1; 60 | cfg.loopback = 1; 61 | config_set(&cfg); 62 | } 63 | -------------------------------------------------------------------------------- /src/table.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Lindenbaum GmbH 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef _TABLE_H_ 19 | #define _TABLE_H_ 20 | 21 | #include "module.h" 22 | 23 | #include "config.h" 24 | 25 | #include "debug.h" 26 | 27 | struct table_entry { 28 | __be32 sender_addr; 29 | __be16 sender_port; 30 | 31 | __be32 receiver_addr; 32 | __be16 receiver_port; 33 | 34 | __be32 sbc_addr; 35 | __be16 sbc_port; 36 | 37 | uint16_t last_sn; 38 | uint16_t offset; 39 | uint8_t offset_set; 40 | uint8_t entry_used; 41 | }; 42 | 43 | struct routing { 44 | __be32 i_src_addr; 45 | __be16 i_src_port; 46 | __be32 i_dst_addr; 47 | __be16 i_dst_port; 48 | 49 | __be32 i_prx_addr; 50 | __be16 i_prx_port; 51 | __be32 e_prx_addr; 52 | __be16 e_prx_port; 53 | 54 | __be32 e_src_addr; 55 | __be16 e_src_port; 56 | __be32 e_dst_addr; 57 | __be16 e_dst_port; 58 | 59 | uint8_t loopback; 60 | 61 | uint8_t smoothing; 62 | }; 63 | 64 | #define TABLE_SIZE 65536 65 | 66 | void table_init(void); 67 | 68 | bool table_get(__be16 index, struct table_entry *entry); 69 | 70 | void table_put(__be16 index, struct table_entry *entry); 71 | 72 | void table_del(__be16 index); 73 | 74 | void table_clr(void); 75 | 76 | typedef void *table_function(struct table_entry *entry, void *arg); 77 | 78 | void *table_atomically(__be16 index, table_function *fn, void *arg); 79 | 80 | bool get_routing(__be16 index, 81 | struct config *cfg, 82 | struct table_entry *entry, 83 | struct routing *routing); 84 | 85 | #ifdef DEBUG 86 | void debug_print_routing(struct routing *rt); 87 | #endif 88 | 89 | #endif // _TABLE_H_ 90 | -------------------------------------------------------------------------------- /src/module.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Lindenbaum GmbH 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef _MODULE_H_ 19 | #define _MODULE_H_ 20 | 21 | #ifdef __KERNEL__ 22 | # include 23 | #else 24 | # ifdef TESTS 25 | # include "../tests/tests.h" 26 | # endif 27 | #endif 28 | 29 | // check for name of the module 30 | #ifndef MODULE_NAME 31 | #error "MODULE_NAME not set" 32 | #endif 33 | 34 | // banner to be used for printk output 35 | #define BANNER KERN_INFO MODULE_NAME " -- " 36 | 37 | // format string constants 38 | #define U8_FMT "%hhu" 39 | #define U16_FMT "%hu" 40 | #define IP_FMT U8_FMT"."U8_FMT"."U8_FMT"."U8_FMT 41 | #define PORT_FMT U16_FMT 42 | #define IP_PORT_FMT IP_FMT":"PORT_FMT 43 | #define CSUM_FMT "%04hx" 44 | 45 | // byte array <-> host byte order integer conversion of IP4 addresses 46 | #define atohl(ip) ((ip[0] << 24) | (ip[1] << 16) | (ip[2] << 8) | (ip[3] << 0)) 47 | #define htoal(ip) { (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, (ip >> 0) & 0xFF, } 48 | 49 | // create local variable "name" of type struct "type", and fill with zeros 50 | #define empty_struct(type, name) struct type name; memset(&name, 0, sizeof(name)) 51 | 52 | /* IP Hooks */ 53 | /* After promisc drops, checksum checks. */ 54 | #define NF_IP_PRE_ROUTING 0 55 | /* If the packet is destined for this box. */ 56 | #define NF_IP_LOCAL_IN 1 57 | /* If the packet is destined for another interface. */ 58 | #define NF_IP_FORWARD 2 59 | /* Packets coming from a local process. */ 60 | #define NF_IP_LOCAL_OUT 3 61 | /* Packets about to hit the wire. */ 62 | #define NF_IP_POST_ROUTING 4 63 | #define NF_IP_NUMHOOKS 5 64 | 65 | // shorter names for ip/udp header field selection 66 | #define S_ADDR ip_header->saddr 67 | #define S_PORT udp_header->source 68 | #define D_ADDR ip_header->daddr 69 | #define D_PORT udp_header->dest 70 | 71 | #endif // _MODULE_H_ 72 | -------------------------------------------------------------------------------- /src/debug.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Lindenbaum GmbH 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "debug.h" 19 | 20 | #ifdef DEBUG 21 | const char *ip_summed_toString(__u8 ip_summed) { 22 | switch(ip_summed) { 23 | case CHECKSUM_NONE: 24 | return "CHECKSUM_NONE"; 25 | case CHECKSUM_UNNECESSARY: 26 | return "CHECKSUM_UNNECESSARY"; 27 | case CHECKSUM_COMPLETE: 28 | return "CHECKSUM_COMPLETE"; 29 | case CHECKSUM_PARTIAL: 30 | return "CHECKSUM_PARTIAL"; 31 | default: 32 | return "CHECKSUM_UNKNOWN"; 33 | } 34 | } 35 | 36 | void debug_print_tuple(const char *msg, 37 | __be32 src_addr, __be16 src_port, 38 | __be32 dst_addr, __be16 dst_port) { 39 | __u8 src_addr_ip[4] = htoal(ntohl(src_addr)); 40 | __u8 dst_addr_ip[4] = htoal(ntohl(dst_addr)); 41 | printk(BANNER "%s "IP_PORT_FMT" -> " IP_PORT_FMT"\n", 42 | msg, 43 | src_addr_ip[0], src_addr_ip[1], src_addr_ip[2], src_addr_ip[3], ntohs(src_port), 44 | dst_addr_ip[0], dst_addr_ip[1], dst_addr_ip[2], dst_addr_ip[3], ntohs(dst_port)); 45 | } 46 | 47 | void debug_print_skb(const char *msg, struct sk_buff *skb, struct iphdr *ip_header, struct udphdr *udp_header) { 48 | debug_print_tuple(msg, S_ADDR, S_PORT, D_ADDR, D_PORT); 49 | 50 | printk(BANNER " id:%hu ttl:%hhu ip_csum:"CSUM_FMT" udp_csum:"CSUM_FMT" dev:%s dst:%p\n", 51 | ntohs(ip_header->id), 52 | ip_header->ttl, 53 | ntohs(ip_header->check), 54 | ntohs(udp_header->check), 55 | skb->dev->name, 56 | skb_dst(skb)); 57 | 58 | printk(BANNER " data:%lu tail:%lu end:%lu nh:%lu th:%lu ip_summed:%s csum_start:"U16_FMT" csum_offset:"U16_FMT"\n", 59 | skb->data - skb->head, 60 | skb_tail_pointer(skb) - skb->head, 61 | skb_end_pointer(skb) - skb->head, 62 | skb_network_header(skb) - skb->head, 63 | skb_transport_header(skb) - skb->head, 64 | ip_summed_toString(skb->ip_summed), 65 | skb->csum_start, 66 | skb->csum_offset); 67 | } 68 | #endif 69 | -------------------------------------------------------------------------------- /dist/lbm_rtp_proxy.spec: -------------------------------------------------------------------------------- 1 | Name: lbm_rtp_proxy 2 | 3 | #################################### 4 | # Specify the current version here: 5 | Version: 1.0.4 6 | Release: 1 7 | #################################### 8 | 9 | Summary: Lindenbaum RTP proxy/relay kernel module 10 | Group: System Environment/Daemons 11 | BuildArch: noarch 12 | License: GPLv3 13 | URL: https://github.com/lindenbaum/lbm_rtp_proxy 14 | Source0: https://github.com/lindenbaum/lbm_rtp_proxy/archive/%{version}.tar.gz 15 | BuildRequires: redhat-rpm-config 16 | Requires: gcc make 17 | Requires: kernel-devel 18 | Requires(post): dkms 19 | Requires(preun): dkms 20 | 21 | %description 22 | A kernel module to proxy/relay and route RTP/RTCP traffic. 23 | 24 | %prep 25 | export LBM_RTP_PROXY_VERSION=%{version}-%{release} 26 | %setup -q 27 | 28 | %install 29 | mkdir -p %{buildroot}%{_usrsrc}/%{name}-%{version}-%{release} 30 | install -D -p -m644 Makefile %{buildroot}%{_usrsrc}/%{name}-%{version}-%{release}/Makefile 31 | install -D -p -m644 src/checksum.c %{buildroot}%{_usrsrc}/%{name}-%{version}-%{release}/src/checksum.c 32 | install -D -p -m644 src/checksum.h %{buildroot}%{_usrsrc}/%{name}-%{version}-%{release}/src/checksum.h 33 | install -D -p -m644 src/command.c %{buildroot}%{_usrsrc}/%{name}-%{version}-%{release}/src/command.c 34 | install -D -p -m644 src/command.h %{buildroot}%{_usrsrc}/%{name}-%{version}-%{release}/src/command.h 35 | install -D -p -m644 src/config.c %{buildroot}%{_usrsrc}/%{name}-%{version}-%{release}/src/config.c 36 | install -D -p -m644 src/config.h %{buildroot}%{_usrsrc}/%{name}-%{version}-%{release}/src/config.h 37 | install -D -p -m644 src/debug.c %{buildroot}%{_usrsrc}/%{name}-%{version}-%{release}/src/debug.c 38 | install -D -p -m644 src/debug.h %{buildroot}%{_usrsrc}/%{name}-%{version}-%{release}/src/debug.h 39 | install -D -p -m644 src/mangle.c %{buildroot}%{_usrsrc}/%{name}-%{version}-%{release}/src/mangle.c 40 | install -D -p -m644 src/mangle.h %{buildroot}%{_usrsrc}/%{name}-%{version}-%{release}/src/mangle.h 41 | install -D -p -m644 src/module.c %{buildroot}%{_usrsrc}/%{name}-%{version}-%{release}/src/module.c 42 | install -D -p -m644 src/module.h %{buildroot}%{_usrsrc}/%{name}-%{version}-%{release}/src/module.h 43 | install -D -p -m644 src/procfs.c %{buildroot}%{_usrsrc}/%{name}-%{version}-%{release}/src/procfs.c 44 | install -D -p -m644 src/procfs.h %{buildroot}%{_usrsrc}/%{name}-%{version}-%{release}/src/procfs.h 45 | install -D -p -m644 src/rewrite.c %{buildroot}%{_usrsrc}/%{name}-%{version}-%{release}/src/rewrite.c 46 | install -D -p -m644 src/rewrite.h %{buildroot}%{_usrsrc}/%{name}-%{version}-%{release}/src/rewrite.h 47 | install -D -p -m644 src/rtcp_packet.h %{buildroot}%{_usrsrc}/%{name}-%{version}-%{release}/src/rtcp_packet.h 48 | install -D -p -m644 src/rtp_packet.h %{buildroot}%{_usrsrc}/%{name}-%{version}-%{release}/src/rtp_packet.h 49 | install -D -p -m644 src/table.c %{buildroot}%{_usrsrc}/%{name}-%{version}-%{release}/src/table.c 50 | install -D -p -m644 src/table.h %{buildroot}%{_usrsrc}/%{name}-%{version}-%{release}/src/table.h 51 | install -D -p -m644 dist/dkms.conf.in %{buildroot}%{_usrsrc}/%{name}-%{version}-%{release}/dkms.conf 52 | sed -i -e "s/__VSN__/%{version}-%{release}/g" %{buildroot}%{_usrsrc}/%{name}-%{version}-%{release}/dkms.conf 53 | install -D -p -m644 dist/lbm_rtp_proxy.conf %{buildroot}%{_sysconfdir}/modules-load.d/lbm_rtp_proxy.conf 54 | 55 | %post 56 | dkms add -m %{name} -v %{version}-%{release} --rpm_safe_upgrade && 57 | dkms build -m %{name} -v %{version}-%{release} --rpm_safe_upgrade && 58 | dkms install -m %{name} -v %{version}-%{release} --rpm_safe_upgrade --force 59 | true 60 | 61 | %preun 62 | dkms uninstall -m %{name} -v %{version}-%{release} --rpm_safe_upgrade 63 | dkms remove -m %{name} -v %{version}-%{release} --rpm_safe_upgrade --all 64 | rmmod %{name} 65 | true 66 | 67 | %files 68 | %{_usrsrc}/%{name}-%{version}-%{release}/ 69 | %{_sysconfdir}/modules-load.d/lbm_rtp_proxy.conf 70 | 71 | %changelog 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | lbm_rtp_proxy 2 | ============= 3 | 4 | A kernel module proxying/relaying RTP/RTCP traffic. 5 | 6 | Attention Developers 7 | -------------------- 8 | 9 | Always **adapt the version** after hacking on this project. 10 | 11 | * Update the `LBM_RTP_PROXY_VERSION` in the [Makefile](./Makefile) 12 | * Update the version in the [RPM build .spec file](./dist/lbm_rtp_proxy.spec) 13 | * Create a git tag for the version, this is important because the source 14 | archive is defined in terms of the version, i.e. 15 | `https://github.com/lindenbaum/lbm_rtp_proxy/archive/%{version}.tar.gz` 16 | 17 | 18 | Netfilter IP Hooks 19 | ------------------ 20 | 21 | The following is a little drawing, that helps understanding the kernels packet 22 | filter/routing chains. 23 | 24 | ``` 25 | +---------------------------------------------------------------------------------------------+ 26 | | | 27 | | N E T F I L T E R I P H O O K S | 28 | | =================================== | 29 | | | 30 | | ------- ------- ------- | 31 | | / (0) / (2) / (4) | 32 | | PRE | +-----------+ | | | POST | 33 | ----> | | ---> | Routing | ---> | FORWARD | -----------+----------> | | ----> 34 | from | ROUTING | +-----------+ | | | | ROUTING | to 35 | wire \ / | \ / | \ / wire 36 | ------- | ------- | ------- 37 | | | +-----------+ | 38 | | | | Routing | | 39 | | | +-----------+ | 40 | | | ^ | 41 | | | | | 42 | | v | | 43 | | ------- ------- | 44 | | / (1) --------- / (3) | 45 | | | LOCAL | | Local | | LOCAL | | 46 | | | | ---> | | ---> | | | 47 | | | IN | | Processes | | OUT | | 48 | | \ / --------- \ / | 49 | | ------- ------- | 50 | | | 51 | +---------------------------------------------------------------------------------------------+ 52 | | | 53 | | (0) After promisc drops, checksum checks | 54 | | (1) If the packet is destined for this box | 55 | | (2) If the packet is destined for another interface | 56 | | (3) Packets coming from a local process | 57 | | (4) Packets about to hit the wire | 58 | | | 59 | +---------------------------------------------------------------------------------------------+ 60 | ``` 61 | -------------------------------------------------------------------------------- /tests/tests.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Lindenbaum GmbH 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef _TESTS_H_ 19 | #define _TESTS_H_ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #if __BYTE_ORDER == __BIG_ENDIAN 34 | # define __BIG_ENDIAN_BITFIELD 35 | #elif __BYTE_ORDER == __LITTLE_ENDIAN 36 | # define __LITTLE_ENDIAN_BITFIELD 37 | #endif 38 | 39 | // "mock out" definitions 40 | 41 | #define KERN_INFO "" 42 | #define printk printf 43 | 44 | #define __be16 __u16 45 | #define __be32 __u32 46 | 47 | #define USHRT_MAX ((u16)(~0U)) 48 | #define SHRT_MAX ((s16)(USHRT_MAX>>1)) 49 | #define SHRT_MIN ((s16)(-SHRT_MAX - 1)) 50 | #define INT_MAX ((int)(~0U>>1)) 51 | #define INT_MIN (-INT_MAX - 1) 52 | #define UINT_MAX (~0U) 53 | #define LONG_MAX ((long)(~0UL>>1)) 54 | #define LONG_MIN (-LONG_MAX - 1) 55 | #define ULONG_MAX (~0UL) 56 | #define LLONG_MAX ((long long)(~0ULL>>1)) 57 | #define LLONG_MIN (-LLONG_MAX - 1) 58 | #define ULLONG_MAX (~0ULL) 59 | 60 | #define THIS_MODULE 0 61 | 62 | // provide spinlock mock definitions 63 | 64 | typedef int spinlock_t; 65 | #define spin_lock_init(_) do{}while(0) 66 | #define spin_lock_bh(_) do{}while(0) 67 | #define spin_unlock_bh(_) do{}while(0) 68 | 69 | // provide sk_buff mock definitions 70 | 71 | struct net_device { 72 | char *name; 73 | int features; 74 | }; 75 | 76 | #define NETIF_F_V4_CSUM 1 77 | 78 | #define CHECKSUM_NONE 0 79 | #define CHECKSUM_UNNECESSARY 1 80 | #define CHECKSUM_COMPLETE 2 81 | #define CHECKSUM_PARTIAL 3 82 | 83 | #define __wsum __u32 84 | #define __sum16 __u16 85 | 86 | #define CSUM_MANGLED_0 -1 87 | 88 | struct sk_buff { 89 | struct net_device *dev; 90 | __u8 ip_summed:2; 91 | union { 92 | __wsum csum; 93 | struct { 94 | __u16 csum_start; 95 | __u16 csum_offset; 96 | }; 97 | }; 98 | unsigned char *head, 99 | *data; 100 | }; 101 | 102 | struct rtable { 103 | int rt_flags; 104 | }; 105 | 106 | #define RTCF_LOCAL 1 107 | 108 | #define skb_dst(a) 0 109 | #define skb_linearize(a) 0 110 | #define skb_network_header(a) (unsigned char *)0 111 | #define skb_transport_header(a) (unsigned char *)0 112 | #define skb_rtable(a) (struct rtable *)0 113 | #define ip_send_check(a) 0 114 | #define ip_fast_csum(a, b) 0 115 | #define csum_tcpudp_magic(a, b, c, d, e) 0 116 | #define csum_partial(a, b, c) 0 117 | 118 | // provide netfilter mock definitions 119 | 120 | struct nf_hook_ops; 121 | typedef unsigned int nf_hookfn(const struct nf_hook_ops *ops, 122 | struct sk_buff *skb, 123 | const struct net_device *in, 124 | const struct net_device *out, 125 | int (*okfn)(struct sk_buff *)); 126 | struct nf_hook_ops { 127 | nf_hookfn *hook; 128 | struct module *owner; 129 | void *priv; 130 | u_int8_t pf; 131 | unsigned int hooknum; 132 | int priority; 133 | }; 134 | 135 | #define NF_IP_PRI_FIRST INT_MIN 136 | #define NF_IP_PRI_FILTER 0 137 | #define NF_IP_PRI_LAST INT_MAX 138 | 139 | #define NF_MAX_HOOKS 8 140 | 141 | #define NF_ACCEPT 1 142 | #define NF_DROP 0 143 | 144 | // provide proc fs mock definitions 145 | 146 | #define gfp_t unsigned 147 | #define GFP_KERNEL 0 148 | 149 | void *kmalloc(size_t size, gfp_t flags); 150 | void kfree(const void *objp); 151 | long copy_from_user(void *to, const void *from, unsigned long n); 152 | 153 | struct inode { 154 | }; 155 | 156 | struct file { 157 | }; 158 | 159 | struct file_operations { 160 | void *owner; 161 | void *open; 162 | void *read; 163 | void *write; 164 | void *llseek; 165 | void *release; 166 | }; 167 | 168 | struct seq_file { 169 | void *private; 170 | }; 171 | 172 | struct seq_operations { 173 | void *start; 174 | void *next; 175 | void *stop; 176 | void *show; 177 | }; 178 | 179 | #define seq_read (void *)0 180 | #define seq_lseek (void *)0 181 | #define seq_release_private (void *)0 182 | 183 | #define umode_t unsigned int 184 | #define S_IRUGO 0 185 | #define S_IWUGO 0 186 | 187 | struct proc_dir_entry { 188 | }; 189 | 190 | // assertion macros 191 | 192 | #define KNRM "\x1B[0m" 193 | #define KRED "\x1B[31m" 194 | #define KGRN "\x1B[32m" 195 | #define KYEL "\x1B[33m" 196 | #define KBLU "\x1B[34m" 197 | #define KMAG "\x1B[35m" 198 | #define KCYN "\x1B[36m" 199 | #define KWHT "\x1B[37m" 200 | 201 | #define assert_equals(expected, actual, file, line) if((expected) != (actual)) { fprintf(stderr, KRED"FAILURE"KNRM" %s:%d: expected: %lld, actual: %lld\n", file, line, (long long)(expected), (long long)(actual)); exit(-1); } 202 | 203 | #endif // _TESTS_H_ 204 | -------------------------------------------------------------------------------- /src/command.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Lindenbaum GmbH 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "command.h" 19 | 20 | #include 21 | 22 | #include "debug.h" 23 | 24 | //////////////////////////////////////////////////////////////////////////////// 25 | // 26 | // command handling functions 27 | // 28 | // "a : : :" 29 | // add proxy route 30 | // 31 | // "d " 32 | // delete proxy route 33 | // 34 | // "c " 35 | // configure proxy IPs 36 | // 37 | // "s 38 | // configure RTP serial number/ssrc smoothing 39 | // 40 | // "l 41 | // configure support for loopback routing 42 | // 43 | // "f" 44 | // flush configuration and table entries by setting it to all zero 45 | // 46 | //////////////////////////////////////////////////////////////////////////////// 47 | 48 | static inline void *update_table_function(struct table_entry *entry, void *arg) { 49 | struct table_entry *ent = arg; 50 | 51 | entry->sender_addr = ent->sender_addr; 52 | entry->sender_port = ent->sender_port; 53 | entry->receiver_addr = ent->receiver_addr; 54 | entry->receiver_port = ent->receiver_port; 55 | entry->sbc_addr = ent->sbc_addr; 56 | entry->sbc_port = ent->sbc_port; 57 | 58 | if(!entry->offset_set) { 59 | uint16_t random_sn; 60 | get_random_bytes(&random_sn, sizeof(random_sn)); 61 | entry->offset = random_sn; 62 | entry->offset_set = 1; 63 | } 64 | 65 | return arg; 66 | } 67 | 68 | static void command_add(const char *parameters) { 69 | uint16_t proxy_port; 70 | 71 | uint8_t sender_ip[4]; 72 | uint16_t sender_port; 73 | 74 | uint8_t receiver_ip[4]; 75 | uint16_t receiver_port; 76 | 77 | uint8_t sbc_ip[4]; 78 | uint16_t sbc_port; 79 | 80 | if(16 == sscanf(parameters, " "PORT_FMT" "IP_PORT_FMT" "IP_PORT_FMT" "IP_PORT_FMT" ", 81 | &proxy_port, 82 | &sender_ip[0], &sender_ip[1], &sender_ip[2], &sender_ip[3], &sender_port, 83 | &receiver_ip[0], &receiver_ip[1], &receiver_ip[2], &receiver_ip[3], &receiver_port, 84 | &sbc_ip[0], &sbc_ip[1], &sbc_ip[2], &sbc_ip[3], &sbc_port)) { 85 | 86 | __be16 index = htons(proxy_port); 87 | 88 | struct table_entry ent = { 89 | .sender_addr = htonl(atohl(sender_ip)), 90 | .sender_port = htons(sender_port), 91 | 92 | .receiver_addr = htonl(atohl(receiver_ip)), 93 | .receiver_port = htons(receiver_port), 94 | 95 | .sbc_addr = htonl(atohl(sbc_ip)), 96 | .sbc_port = htons(sbc_port), 97 | }; 98 | 99 | table_atomically(index, update_table_function, &ent); 100 | } 101 | else { 102 | debug_printk(BANNER "command a failed\n"); 103 | } 104 | } 105 | 106 | static void command_delete(const char *parameters) { 107 | uint16_t proxy_port; 108 | 109 | if(1 == sscanf(parameters, " "PORT_FMT" ", 110 | &proxy_port)) { 111 | __be16 key = htons(proxy_port); 112 | 113 | table_del(key); 114 | } 115 | else { 116 | debug_printk(BANNER "command d failed\n"); 117 | } 118 | } 119 | 120 | static void command_configure(const char *parameters) { 121 | uint8_t int_proxy_ip[4]; 122 | uint8_t ext_proxy_ip[4]; 123 | 124 | if(8 == sscanf(parameters, " "IP_FMT" "IP_FMT" ", 125 | &int_proxy_ip[0], &int_proxy_ip[1], &int_proxy_ip[2], &int_proxy_ip[3], 126 | &ext_proxy_ip[0], &ext_proxy_ip[1], &ext_proxy_ip[2], &ext_proxy_ip[3])) { 127 | struct config cfg; 128 | config_get(&cfg); 129 | cfg.int_proxy_addr = htonl(atohl(int_proxy_ip)); 130 | cfg.ext_proxy_addr = htonl(atohl(ext_proxy_ip)); 131 | config_set(&cfg); 132 | } 133 | else { 134 | debug_printk(BANNER "command c failed\n"); 135 | } 136 | } 137 | 138 | static void command_smoothing(const char *parameters) { 139 | uint8_t smoothing; 140 | 141 | if(1 == sscanf(parameters, " "U8_FMT" ", 142 | &smoothing)) { 143 | struct config cfg; 144 | config_get(&cfg); 145 | cfg.smoothing = smoothing; 146 | config_set(&cfg); 147 | } 148 | else { 149 | debug_printk(BANNER "command s failed\n"); 150 | } 151 | } 152 | 153 | static void command_loopback(const char *parameters) { 154 | uint8_t loopback; 155 | 156 | if(1 == sscanf(parameters, " "U8_FMT" ", 157 | &loopback)) { 158 | struct config cfg; 159 | config_get(&cfg); 160 | cfg.loopback = loopback; 161 | config_set(&cfg); 162 | } 163 | else { 164 | debug_printk(BANNER "command s failed\n"); 165 | } 166 | } 167 | 168 | static void command_flush(const char *parameters) { 169 | if(0 == sscanf(parameters, " ")) { 170 | config_clr(); 171 | table_clr(); 172 | } 173 | else { 174 | debug_printk(BANNER "command f failed\n"); 175 | } 176 | } 177 | 178 | // required by procfs.c 179 | bool handle_command(const char *command) { 180 | debug_printk(BANNER "command: %s\n", command); 181 | switch(command[0]) { 182 | case 'a': 183 | command_add(&command[1]); 184 | return true; 185 | case 'd': 186 | command_delete(&command[1]); 187 | return true; 188 | case 'c': 189 | command_configure(&command[1]); 190 | return true; 191 | case 's': 192 | command_smoothing(&command[1]); 193 | return true; 194 | case 'l': 195 | command_loopback(&command[1]); 196 | return true; 197 | case 'f': 198 | command_flush(&command[1]); 199 | return true; 200 | default: 201 | return false; 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /src/mangle.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Lindenbaum GmbH 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "mangle.h" 19 | 20 | #include 21 | 22 | static inline bool get_ip_and_udp_headers(struct sk_buff *skb, struct iphdr **ip_header_out, struct udphdr **udp_header_out) { 23 | if(skb) { 24 | if(!skb_linearize(skb)) { 25 | struct iphdr *ip_header = (struct iphdr *)skb_network_header(skb); 26 | if(ip_header) { 27 | if (ip_header->protocol == IPPROTO_UDP) { 28 | struct udphdr *udp_header = (struct udphdr *)skb_transport_header(skb); 29 | if(udp_header) { 30 | if(ip_header_out) { 31 | *ip_header_out = ip_header; 32 | } 33 | if(udp_header_out) { 34 | *udp_header_out = udp_header; 35 | } 36 | return true; 37 | } 38 | } 39 | } 40 | } 41 | } 42 | return false; 43 | } 44 | 45 | //////////////////////////////////////////////////////////////////////////////// 46 | // GENERIC HOOK FUNCTION 47 | //////////////////////////////////////////////////////////////////////////////// 48 | 49 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) 50 | static unsigned int generic_hook_func(const struct nf_hook_ops *ops, 51 | struct sk_buff *skb, 52 | const struct net_device *_in, 53 | const struct net_device *_out, 54 | const struct nf_hook_state *state) { 55 | struct mangle_hook *mangle_hook = ops->priv; 56 | #else 57 | static unsigned int generic_hook_func(void *priv, 58 | struct sk_buff *skb, 59 | const struct nf_hook_state *state) { 60 | struct mangle_hook *mangle_hook = priv; 61 | #endif 62 | if(mangle_hook) { 63 | if(mangle_hook->name) { 64 | struct iphdr *ip_header; 65 | struct udphdr *udp_header; 66 | if(get_ip_and_udp_headers(skb, &ip_header, &udp_header)) { 67 | if(mangle_hook->fn) { 68 | // get internal/external proxy IPs from config 69 | struct config cfg; 70 | config_get(&cfg); 71 | { 72 | // lookup entry for destination port of incoming UDP packet 73 | __be16 index = udp_header->dest; 74 | struct table_entry ent; 75 | struct routing rt; 76 | // if entry is found 77 | if(get_routing(index, &cfg, &ent, &rt)) { 78 | debug_print_skb(mangle_hook->name, skb, ip_header, udp_header); 79 | if(state->hook == NF_IP_PRE_ROUTING || state->hook == NF_IP_LOCAL_OUT) { 80 | handle_incoming_checksums(skb, ip_header, udp_header); 81 | } 82 | switch(mangle_hook->fn(ip_header, udp_header, &ent, &rt)) { 83 | case NF_ACCEPT: 84 | if(state->hook == NF_IP_LOCAL_OUT) { 85 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) 86 | int err = ip_route_me_harder(skb, RTN_UNSPEC); 87 | #elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 78) 88 | int err = ip_route_me_harder(state->net, skb, RTN_UNSPEC); 89 | #else 90 | int err = ip_route_me_harder(state->net, state->sk, skb, RTN_UNSPEC); 91 | #endif 92 | if (err < 0) { 93 | debug_printk(BANNER " ip_route_me_harder FAILED -> DROP\n"); 94 | return NF_DROP_ERR(err); 95 | } 96 | } 97 | else if(state->hook == NF_IP_POST_ROUTING) { 98 | handle_outgoing_checksums(skb, ip_header, udp_header); 99 | } 100 | return NF_ACCEPT; 101 | case NF_DROP: 102 | debug_printk(BANNER " packet could not be routed -> DROP\n"); 103 | return NF_DROP; 104 | } 105 | } 106 | } 107 | } 108 | } 109 | } 110 | } 111 | return NF_ACCEPT; 112 | } 113 | 114 | //////////////////////////////////////////////////////////////////////////////// 115 | // registration and unregistration of netfilter hooks 116 | //////////////////////////////////////////////////////////////////////////////// 117 | 118 | static int hook_count = 0; 119 | static struct nf_hook_ops hook_ops[NF_MAX_HOOKS]; 120 | 121 | void register_nf_hooks(void) { 122 | struct mangle_hook *mangle_hooks; 123 | hook_count = get_mangle_hooks(&mangle_hooks); 124 | if(hook_count > NF_MAX_HOOKS) { 125 | debug_printk(BANNER "too many hooks (%d), setting to 0", hook_count); 126 | hook_count = 0; 127 | } 128 | if(hook_count > 0) { 129 | int i; 130 | for(i = 0; i < hook_count; i++) { 131 | hook_ops[i].hook = generic_hook_func; 132 | hook_ops[i].hooknum = mangle_hooks[i].hooknum; 133 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) 134 | hook_ops[i].owner = THIS_MODULE; 135 | #endif 136 | hook_ops[i].priv = &mangle_hooks[i]; 137 | hook_ops[i].pf = PF_INET; 138 | hook_ops[i].priority = mangle_hooks[i].priority; 139 | } 140 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) 141 | nf_register_hooks(hook_ops, hook_count); 142 | #else 143 | // TODO init_net might not always be appropriate 144 | // https://stackoverflow.com/a/13355999 145 | nf_register_net_hooks(&init_net, hook_ops, hook_count); 146 | #endif 147 | } 148 | } 149 | 150 | void unregister_nf_hooks(void) { 151 | if(hook_count > 0) { 152 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) 153 | nf_unregister_hooks(hook_ops, hook_count); 154 | #else 155 | // TODO init_net might not always be appropriate 156 | // https://stackoverflow.com/a/13355999 157 | nf_unregister_net_hooks(&init_net, hook_ops, hook_count); 158 | #endif 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /tests/rtp_packet_test.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Lindenbaum GmbH 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "tests.h" 19 | 20 | #include "../src/rtp_packet.h" 21 | #include "../src/rtcp_packet.h" 22 | 23 | /* 24 | // UDP 25 | e8 89 80 01 00 20 d6 11 26 | // RR 27 | 80 c9 00 01 c1 85 9f e9 28 | // SDES 29 | 81 ca 00 03 c1 85 9f e9 01 04 53 4e 4f 4d 00 00 30 | */ 31 | 32 | uint8_t RR[] = { 33 | 0xe8, 0x89, 0x80, 0x01, 0x00, 0x20, 0xd6, 0x11, 34 | 0x80, 0xc9, 0x00, 0x01, 0xc1, 0x85, 0x9f, 0xe9, 35 | 0x81, 0xca, 0x00, 0x03, 0xc1, 0x85, 0x9f, 0xe9, 36 | 0x01, 0x04, 0x53, 0x4e, 0x4f, 0x4d, 0x00, 0x00, 37 | }; 38 | 39 | /* 40 | // UDP 41 | e8 89 80 01 00 4c fc 1b 42 | // SR 43 | 81 c8 00 0c c1 85 9f e9 00 00 8c b1 1e b8 00 00 44 | 00 00 00 00 00 00 00 f4 00 00 98 80 2a 6d 69 48 45 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 46 | 00 00 00 00 47 | // SDES 48 | 81 ca 00 03 c1 85 9f e9 01 04 53 4e 4f 4d 00 00 49 | */ 50 | 51 | uint8_t SR0[] = { 52 | 0xe8, 0x89, 0x80, 0x01, 0x00, 0x4c, 0xfc, 0x1b, 53 | 0x81, 0xc8, 0x00, 0x0c, 0xc1, 0x85, 0x9f, 0xe9, 54 | 0x00, 0x00, 0x8c, 0xb1, 0x1e, 0xb8, 0x00, 0x00, 55 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf4, 56 | 0x00, 0x00, 0x98, 0x80, 0x2a, 0x6d, 0x69, 0x48, 57 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 58 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 59 | 0x00, 0x00, 0x00, 0x00, 0x81, 0xca, 0x00, 0x03, 60 | 0xc1, 0x85, 0x9f, 0xe9, 0x01, 0x04, 0x53, 0x4e, 61 | 0x4f, 0x4d, 0x00, 0x00, 62 | }; 63 | 64 | /* 65 | // UDP 66 | e8 89 80 01 00 4c 5e dc 67 | // SR 68 | 81 c8 00 0c c1 85 9f e9 00 00 8c b6 1e b8 00 00 69 | 00 00 00 00 00 00 01 ee 00 01 34 c0 2a 6d 69 48 70 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 71 | 00 00 00 00 72 | // SDES 73 | 81 ca 00 03 c1 85 9f e9 01 04 53 4e 4f 4d 00 00 74 | */ 75 | 76 | uint8_t SR1[] = { 77 | 0xe8, 0x89, 0x80, 0x01, 0x00, 0x4c, 0x5e, 0xdc, 78 | 0x81, 0xc8, 0x00, 0x0c, 0xc1, 0x85, 0x9f, 0xe9, 79 | 0x00, 0x00, 0x8c, 0xb6, 0x1e, 0xb8, 0x00, 0x00, 80 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 81 | 0x00, 0x01, 0x34, 0xc0, 0x2a, 0x6d, 0x69, 0x48, 82 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 83 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 84 | 0x00, 0x00, 0x00, 0x00, 0x81, 0xca, 0x00, 0x03, 85 | 0xc1, 0x85, 0x9f, 0xe9, 0x01, 0x04, 0x53, 0x4e, 86 | 0x4f, 0x4d, 0x00, 0x00, 87 | }; 88 | 89 | /* 90 | // UDP 91 | e8 89 80 01 00 1c 55 4d 92 | // BYE 93 | 81 cb 00 04 c1 85 9f e9 0b 43 61 6c 6c 20 65 6e 94 | 64 65 64 00 95 | */ 96 | 97 | uint8_t BYE[] = { 98 | 0xe8, 0x89, 0x80, 0x01, 0x00, 0x1c, 0x55, 0x4d, 99 | 0x81, 0xcb, 0x00, 0x04, 0xc1, 0x85, 0x9f, 0xe9, 100 | 0x0b, 0x43, 0x61, 0x6c, 0x6c, 0x20, 0x65, 0x6e, 101 | 0x64, 0x65, 0x64, 0x00, 102 | }; 103 | 104 | uint8_t rtp_data[] = { 105 | 0x80, 0x08, 0x21, 0x55, 0x00, 0x00, 0x03, 0x20, 0x2a, 0x6d, 0x69, 0x48, 0xd5, 0xd5, 0xd5, 0xd5, 106 | 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 107 | 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 108 | 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 109 | 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 110 | 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 111 | 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 112 | 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 113 | 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 114 | 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 115 | 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 116 | }; 117 | 118 | void rewrite_rtcp_test(struct udphdr *udp_header, __be32 SSRC) { 119 | int32_t remaining = ntohs(udp_header->len); 120 | uint8_t *data = (uint8_t *)udp_header; 121 | if(remaining >= sizeof(struct udphdr)) { 122 | data += sizeof(struct udphdr); 123 | remaining -= sizeof(struct udphdr); 124 | while(remaining >= sizeof(struct rtcp_packet)) { 125 | struct rtcp_packet *packet = (struct rtcp_packet *)data; 126 | if(packet->V == 2) { 127 | switch(packet->PT) { 128 | case SR_PACKET_TYPE: 129 | case RR_PACKET_TYPE: 130 | case SDES_PACKET_TYPE: 131 | case BYE_PACKET_TYPE: 132 | case APP_PACKET_TYPE: { 133 | int32_t len = ((int32_t)ntohs(packet->length) + 1) * 4; 134 | packet->SSRC = SSRC; 135 | data += len; 136 | remaining -= len; 137 | break; 138 | } 139 | default: 140 | return; 141 | } 142 | } 143 | else { 144 | return; 145 | } 146 | } 147 | } 148 | else { 149 | return; 150 | } 151 | } 152 | 153 | int main(int argc, char **argv) { 154 | //printf("%d\n", sizeof(RR) / sizeof(RR[0])); 155 | assert_equals(htonl(0xc1859fe9), *(__be32 *)&RR[12], __FILE__, __LINE__); 156 | assert_equals(htonl(0xc1859fe9), *(__be32 *)&RR[20], __FILE__, __LINE__); 157 | rewrite_rtcp_test((struct udphdr *)RR, 0x12345678); 158 | assert_equals(0x12345678, *(__be32 *)&RR[12], __FILE__, __LINE__); 159 | assert_equals(0x12345678, *(__be32 *)&RR[20], __FILE__, __LINE__); 160 | 161 | assert_equals(htonl(0xc1859fe9), *(__be32 *)&SR0[12], __FILE__, __LINE__); 162 | assert_equals(htonl(0xc1859fe9), *(__be32 *)&SR0[64], __FILE__, __LINE__); 163 | rewrite_rtcp_test((struct udphdr *)SR0, 0x23456789); 164 | assert_equals(0x23456789, *(__be32 *)&SR0[12], __FILE__, __LINE__); 165 | assert_equals(0x23456789, *(__be32 *)&SR0[64], __FILE__, __LINE__); 166 | 167 | assert_equals(htonl(0xc1859fe9), *(__be32 *)&SR1[12], __FILE__, __LINE__); 168 | assert_equals(htonl(0xc1859fe9), *(__be32 *)&SR1[64], __FILE__, __LINE__); 169 | rewrite_rtcp_test((struct udphdr *)SR1, 0x3456789a); 170 | assert_equals(0x3456789a, *(__be32 *)&SR1[12], __FILE__, __LINE__); 171 | assert_equals(0x3456789a, *(__be32 *)&SR1[64], __FILE__, __LINE__); 172 | 173 | assert_equals(htonl(0xc1859fe9), *(__be32 *)&BYE[12], __FILE__, __LINE__); 174 | rewrite_rtcp_test((struct udphdr *)BYE, 0x456789ab); 175 | assert_equals(0x456789ab, *(__be32 *)&BYE[12], __FILE__, __LINE__); 176 | 177 | printf(KGRN"SUCCESS"KNRM"\n"); 178 | exit(0); 179 | } 180 | -------------------------------------------------------------------------------- /src/table.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Lindenbaum GmbH 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "table.h" 19 | 20 | struct table_row { 21 | spinlock_t lock; 22 | struct table_entry entry; 23 | }; 24 | 25 | static struct table_row table[TABLE_SIZE]; 26 | 27 | static inline bool is_entry_valid( struct table_entry *entry) { 28 | return 29 | entry->receiver_addr && entry->receiver_port && 30 | entry->sbc_addr && entry->sbc_port; 31 | } 32 | 33 | void table_init(void) { 34 | int index; 35 | for(index = 0; index < TABLE_SIZE; index++) { 36 | spin_lock_init(&table[index].lock); 37 | } 38 | table_clr(); 39 | } 40 | 41 | bool table_get(__be16 index, struct table_entry *entry) { 42 | spin_lock_bh(&table[index].lock); 43 | *entry = table[index].entry; 44 | spin_unlock_bh(&table[index].lock); 45 | return is_entry_valid(entry); 46 | } 47 | 48 | void table_put(__be16 index, struct table_entry *entry) { 49 | spin_lock_bh(&table[index].lock); 50 | table[index].entry = *entry; 51 | spin_unlock_bh(&table[index].lock); 52 | } 53 | 54 | void table_del(__be16 index) { 55 | empty_struct(table_entry, empty); 56 | table_put(index, &empty); 57 | } 58 | 59 | void table_clr(void) { 60 | int index; 61 | for(index = 0; index < TABLE_SIZE; index++) { 62 | table_del(index); 63 | } 64 | } 65 | 66 | void *table_atomically(__be16 index, table_function *fn, void *arg) { 67 | if(fn) { 68 | void *result = NULL; 69 | spin_lock_bh(&table[index].lock); 70 | result = fn(&table[index].entry, arg); 71 | spin_unlock_bh(&table[index].lock); 72 | return result; 73 | } 74 | else { 75 | return NULL; 76 | } 77 | } 78 | 79 | static inline void init_routing(__be16 index, 80 | struct config *cfg, 81 | struct table_entry *entry, 82 | struct routing *routing) { 83 | __be32 i_src_addr = entry->sender_addr; 84 | __be16 i_src_port = entry->sender_port; 85 | __be32 i_dst_addr = entry->receiver_addr; 86 | __be16 i_dst_port = entry->receiver_port; 87 | 88 | __be32 i_prx_addr = cfg->int_proxy_addr; 89 | __be16 i_prx_port = index; 90 | __be32 e_prx_addr = cfg->ext_proxy_addr; 91 | __be16 e_prx_port = index; 92 | 93 | __be32 e_src_addr = entry->sbc_addr; 94 | __be16 e_src_port = entry->sbc_port; 95 | __be32 e_dst_addr = entry->sbc_addr; 96 | __be16 e_dst_port = entry->sbc_port; 97 | 98 | uint8_t smoothing = cfg->smoothing; 99 | 100 | if(cfg->loopback && i_dst_addr == i_prx_addr && i_dst_port == i_prx_port) { 101 | routing->i_src_addr = e_src_addr; 102 | routing->i_src_port = e_src_port; 103 | routing->i_dst_addr = e_dst_addr; 104 | routing->i_dst_port = e_dst_port; 105 | 106 | routing->i_prx_addr = e_prx_addr; 107 | routing->i_prx_port = e_prx_port; 108 | routing->e_prx_addr = e_prx_addr; 109 | routing->e_prx_port = e_prx_port; 110 | 111 | routing->e_src_addr = e_src_addr; 112 | routing->e_src_port = e_src_port; 113 | routing->e_dst_addr = e_dst_addr; 114 | routing->e_dst_port = e_dst_port; 115 | 116 | routing->loopback = 1; 117 | } 118 | else { 119 | routing->i_src_addr = i_src_addr; 120 | routing->i_src_port = i_src_port; 121 | routing->i_dst_addr = i_dst_addr; 122 | routing->i_dst_port = i_dst_port; 123 | 124 | routing->i_prx_addr = i_prx_addr; 125 | routing->i_prx_port = i_prx_port; 126 | routing->e_prx_addr = e_prx_addr; 127 | routing->e_prx_port = e_prx_port; 128 | 129 | routing->e_src_addr = e_src_addr; 130 | routing->e_src_port = e_src_port; 131 | routing->e_dst_addr = e_dst_addr; 132 | routing->e_dst_port = e_dst_port; 133 | 134 | routing->loopback = 0; 135 | } 136 | 137 | routing->smoothing = smoothing; 138 | } 139 | 140 | bool get_routing(__be16 index, 141 | struct config *cfg, 142 | struct table_entry *entry, 143 | struct routing *routing) { 144 | if(table_get(index, entry)) { 145 | init_routing(index, cfg, entry, routing); 146 | if(cfg->loopback && entry->sbc_addr == cfg->ext_proxy_addr) { 147 | __be16 ind = entry->sbc_port; 148 | struct table_entry ent; 149 | if(table_get(ind, &ent)) { 150 | struct routing tmp; 151 | init_routing(ind, cfg, &ent, &tmp); 152 | 153 | routing->e_prx_addr = tmp.i_prx_addr; 154 | routing->e_prx_port = tmp.i_prx_port; 155 | routing->e_src_addr = tmp.i_src_addr; 156 | routing->e_src_port = tmp.i_src_port; 157 | routing->e_dst_addr = tmp.i_dst_addr; 158 | routing->e_dst_port = tmp.i_dst_port; 159 | } 160 | } 161 | return true; 162 | } 163 | return false; 164 | } 165 | 166 | #ifdef DEBUG 167 | void debug_print_routing(struct routing *rt) { 168 | uint8_t i_src_addr[4] = htoal(ntohl(rt->i_src_addr)); 169 | uint16_t i_src_port = ntohs(rt->i_src_port); 170 | uint8_t i_dst_addr[4] = htoal(ntohl(rt->i_dst_addr)); 171 | uint16_t i_dst_port = ntohs(rt->i_dst_port); 172 | uint8_t i_prx_addr[4] = htoal(ntohl(rt->i_prx_addr)); 173 | uint16_t i_prx_port = ntohs(rt->i_prx_port); 174 | uint8_t e_prx_addr[4] = htoal(ntohl(rt->e_prx_addr)); 175 | uint16_t e_prx_port = ntohs(rt->e_prx_port); 176 | uint8_t e_src_addr[4] = htoal(ntohl(rt->e_src_addr)); 177 | uint16_t e_src_port = ntohs(rt->e_src_port); 178 | uint8_t e_dst_addr[4] = htoal(ntohl(rt->e_dst_addr)); 179 | uint16_t e_dst_port = ntohs(rt->e_dst_port); 180 | 181 | if(rt->loopback) { 182 | printk(BANNER "ROUTING (loopback)\n"); 183 | } 184 | else { 185 | printk(BANNER "ROUTING\n"); 186 | } 187 | 188 | printk(BANNER "=> ("IP_PORT_FMT" -> "IP_PORT_FMT") ~> ("IP_PORT_FMT" -> "IP_PORT_FMT")\n", 189 | i_src_addr[0],i_src_addr[1],i_src_addr[2],i_src_addr[3],i_src_port, 190 | i_prx_addr[0],i_prx_addr[1],i_prx_addr[2],i_prx_addr[3],i_prx_port, 191 | e_prx_addr[0],e_prx_addr[1],e_prx_addr[2],e_prx_addr[3],e_prx_port, 192 | e_dst_addr[0],e_dst_addr[1],e_dst_addr[2],e_dst_addr[3],e_dst_port); 193 | printk(BANNER " < ("IP_PORT_FMT" -> "IP_PORT_FMT") ~> ("IP_PORT_FMT" -> "IP_PORT_FMT")\n", 194 | e_src_addr[0],e_src_addr[1],e_src_addr[2],e_src_addr[3],e_src_port, 195 | e_prx_addr[0],e_prx_addr[1],e_prx_addr[2],e_prx_addr[3],e_prx_port, 196 | i_prx_addr[0],i_prx_addr[1],i_prx_addr[2],i_prx_addr[3],i_prx_port, 197 | i_dst_addr[0],i_dst_addr[1],i_dst_addr[2],i_dst_addr[3],i_dst_port); 198 | } 199 | #endif 200 | -------------------------------------------------------------------------------- /src/procfs.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Lindenbaum GmbH 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "procfs.h" 19 | 20 | #include "config.h" 21 | #include "table.h" 22 | 23 | #include "debug.h" 24 | 25 | #include 26 | 27 | //////////////////////////////////////////////////////////////////////////////// 28 | // 29 | // proc file read handling: output non-empty table entries 30 | // 31 | //////////////////////////////////////////////////////////////////////////////// 32 | 33 | static int next_table_index(int index) { 34 | struct table_entry entry; 35 | while(1) { 36 | ++index; 37 | if(index < TABLE_SIZE) { 38 | if(table_get(index, &entry)) { 39 | break; 40 | } 41 | else { 42 | continue; 43 | } 44 | } 45 | else { 46 | return 0; 47 | } 48 | } 49 | return index; 50 | } 51 | 52 | static void seq_show_table_entry(struct seq_file *seq, uint16_t index, struct table_entry *ent, struct config *cfg) { 53 | if(!index) { 54 | uint8_t int_proxy_ip[4] = htoal(ntohl(cfg->int_proxy_addr)); 55 | uint8_t ext_proxy_ip[4] = htoal(ntohl(cfg->ext_proxy_addr)); 56 | uint8_t smoothing = cfg->smoothing; 57 | uint8_t loopback = cfg->loopback; 58 | seq_printf(seq, "config:" " int_proxy_addr: "IP_FMT " ext_proxy_addr: "IP_FMT" smoothing: "U8_FMT" loopback: "U8_FMT"\n", 59 | int_proxy_ip[0], int_proxy_ip[1], int_proxy_ip[2], int_proxy_ip[3], 60 | ext_proxy_ip[0], ext_proxy_ip[1], ext_proxy_ip[2], ext_proxy_ip[3], 61 | smoothing, loopback); 62 | } 63 | else { 64 | uint8_t int_proxy_ip[4] = htoal(ntohl(cfg->int_proxy_addr)); 65 | uint8_t ext_proxy_ip[4] = htoal(ntohl(cfg->ext_proxy_addr)); 66 | uint16_t proxy_port = ntohs(index); 67 | 68 | uint8_t sender_ip[4] = htoal(ntohl(ent->sender_addr)); 69 | uint16_t sender_port = ntohs(ent->sender_port); 70 | 71 | uint8_t receiver_ip[4] = htoal(ntohl(ent->receiver_addr)); 72 | uint16_t receiver_port = ntohs(ent->receiver_port); 73 | 74 | uint8_t sbc_ip[4] = htoal(ntohl(ent->sbc_addr)); 75 | uint16_t sbc_port = ntohs(ent->sbc_port); 76 | 77 | seq_printf(seq, 78 | "=> ("IP_PORT_FMT" -> "IP_PORT_FMT") ~> ("IP_PORT_FMT" -> "IP_PORT_FMT")\n", 79 | sender_ip[0], sender_ip[1], sender_ip[2], sender_ip[3], sender_port, 80 | int_proxy_ip[0], int_proxy_ip[1], int_proxy_ip[2], int_proxy_ip[3], proxy_port, 81 | ext_proxy_ip[0], ext_proxy_ip[1], ext_proxy_ip[2], ext_proxy_ip[3], proxy_port, 82 | sbc_ip[0], sbc_ip[1], sbc_ip[2], sbc_ip[3], sbc_port); 83 | seq_printf(seq, 84 | " < ("IP_PORT_FMT" -> "IP_PORT_FMT") ~> ("IP_PORT_FMT" -> "IP_PORT_FMT")\n", 85 | sbc_ip[0], sbc_ip[1], sbc_ip[2], sbc_ip[3], sbc_port, 86 | ext_proxy_ip[0], ext_proxy_ip[1], ext_proxy_ip[2], ext_proxy_ip[3], proxy_port, 87 | int_proxy_ip[0], int_proxy_ip[1], int_proxy_ip[2], int_proxy_ip[3], proxy_port, 88 | receiver_ip[0], receiver_ip[1], receiver_ip[2], receiver_ip[3], receiver_port); 89 | } 90 | } 91 | 92 | struct iter { 93 | int index; 94 | }; 95 | 96 | static void *rtp_proxy_seq_start(struct seq_file *seq, loff_t *pos) { 97 | int position = (int)*pos; 98 | struct iter *iter = seq->private; 99 | if(!position) { 100 | iter->index = 0; 101 | return iter; 102 | } 103 | else { 104 | int index = 0; 105 | while(position >= 0) { 106 | --position; 107 | index = next_table_index(index); 108 | if(!index) { 109 | break; 110 | } 111 | } 112 | if(index) { 113 | iter->index = index; 114 | return iter; 115 | } 116 | return NULL; 117 | } 118 | } 119 | 120 | static void *rtp_proxy_seq_next(struct seq_file *seq, void *v, loff_t *pos) { 121 | struct iter *iter = v; 122 | int index = iter->index; 123 | ++*pos; 124 | index = next_table_index(index); 125 | if(index) { 126 | iter->index = index; 127 | return iter; 128 | } 129 | return NULL; 130 | } 131 | 132 | static void rtp_proxy_seq_stop(struct seq_file *seq, void *v) { 133 | // do nothing 134 | } 135 | 136 | static int rtp_proxy_seq_show(struct seq_file *seq, void *v) { 137 | struct iter *iter = v; 138 | int index = iter->index; 139 | struct table_entry ent; 140 | struct config cfg; 141 | table_get(index, &ent); 142 | config_get(&cfg); 143 | seq_show_table_entry(seq, index, &ent, &cfg); 144 | return 0; 145 | } 146 | 147 | static struct seq_operations rtp_proxy_seq_ops = { 148 | .start = rtp_proxy_seq_start, 149 | .next = rtp_proxy_seq_next, 150 | .stop = rtp_proxy_seq_stop, 151 | .show = rtp_proxy_seq_show, 152 | }; 153 | 154 | static int rtp_proxy_open(struct inode *inode, struct file *file) { 155 | return seq_open_private(file, &rtp_proxy_seq_ops, sizeof(struct iter)); 156 | } 157 | 158 | //////////////////////////////////////////////////////////////////////////////// 159 | // 160 | // proc file write handling: read and dispatch commands 161 | // 162 | //////////////////////////////////////////////////////////////////////////////// 163 | 164 | #define WRITE_BUF_SIZE 256 165 | static ssize_t rtp_proxy_write(struct file *file, const char *user_buffer, size_t len, loff_t *off) { 166 | size_t size = WRITE_BUF_SIZE; 167 | char *kernel_buffer = kmalloc(size, GFP_KERNEL); 168 | if(!kernel_buffer) { 169 | return -ENOMEM; 170 | } 171 | 172 | if(len < size) { 173 | size = len; 174 | } 175 | if(copy_from_user(kernel_buffer, user_buffer, size)) { 176 | kfree(kernel_buffer); 177 | return -EFAULT; 178 | } 179 | if(size >= WRITE_BUF_SIZE) { 180 | size = WRITE_BUF_SIZE - 1; 181 | } 182 | kernel_buffer[size] = '\0'; 183 | 184 | if(size > 0) { 185 | if(!handle_command(kernel_buffer)) { 186 | debug_printk(BANNER "command %s failed\n", kernel_buffer); 187 | } 188 | } 189 | 190 | kfree(kernel_buffer); 191 | return size; 192 | } 193 | 194 | //////////////////////////////////////////////////////////////////////////////// 195 | // 196 | // proc file creation and removal 197 | // 198 | //////////////////////////////////////////////////////////////////////////////// 199 | 200 | #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 5, 0) 201 | static const struct file_operations rtp_proxy_file_ops = { 202 | .owner = THIS_MODULE, 203 | .open = rtp_proxy_open, 204 | .write = rtp_proxy_write, 205 | .read = seq_read, 206 | .llseek = seq_lseek, 207 | .release = seq_release_private, 208 | }; 209 | #else 210 | static const struct proc_ops rtp_proxy_file_ops = { 211 | .proc_open = rtp_proxy_open, 212 | .proc_write = rtp_proxy_write, 213 | .proc_read = seq_read, 214 | .proc_lseek = seq_lseek, 215 | .proc_release = seq_release_private 216 | }; 217 | #endif 218 | 219 | 220 | void proc_file_create(void) { 221 | proc_create(MODULE_NAME, S_IRUGO | S_IWUGO, NULL, &rtp_proxy_file_ops); 222 | } 223 | 224 | void proc_file_remove(void) { 225 | remove_proc_entry(MODULE_NAME, NULL); 226 | } 227 | -------------------------------------------------------------------------------- /src/rtp_packet.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Lindenbaum GmbH 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef _RTP_PACKET_H_ 19 | #define _RTP_PACKET_H_ 20 | 21 | struct rtp_packet { 22 | #if defined(__BIG_ENDIAN_BITFIELD) 23 | uint8_t V:2; 24 | uint8_t P:1; 25 | uint8_t X:1; 26 | uint8_t CC:4; 27 | 28 | uint8_t M:1; 29 | uint8_t PT:7; 30 | #elif defined(__LITTLE_ENDIAN_BITFIELD) 31 | uint8_t CC:4; 32 | uint8_t X:1; 33 | uint8_t P:1; 34 | uint8_t V:2; 35 | 36 | uint8_t PT:7; 37 | uint8_t M:1; 38 | #else 39 | # error "this endianness is not supported" 40 | #endif 41 | 42 | __be16 SN; 43 | 44 | __be32 TS; 45 | 46 | __be32 SSRC; 47 | 48 | // __be32 CSRC[15]; // actually 0-15, depending on value of CC 49 | 50 | // ... 51 | }; 52 | 53 | /* [RFC 1889] 54 | 55 | 5.1 RTP Fixed Header Fields 56 | 57 | The RTP header has the following format: 58 | 59 | 60 | 0 1 2 3 61 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 62 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 63 | |V=2|P|X| CC |M| PT | sequence number | 64 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 65 | | timestamp | 66 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 67 | | synchronization source (SSRC) identifier | 68 | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 69 | | contributing source (CSRC) identifiers | 70 | | .... | 71 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 72 | 73 | The first twelve octets are present in every RTP packet, while the 74 | list of CSRC identifiers is present only when inserted by a mixer. The 75 | fields have the following meaning: 76 | 77 | version (V): 2 bits 78 | This field identifies the version of RTP. The version defined by this 79 | specification is two (2). (The value 1 is used by the first draft 80 | version of RTP and the value 0 is used by the protocol initially 81 | implemented in the "vat" audio tool.) padding (P): 1 bit If the 82 | padding bit is set, the packet contains one or more additional padding 83 | octets at the end which are not part of the payload. The last octet of 84 | the padding contains a count of how many padding octets should be 85 | ignored. Padding may be needed by some encryption algorithms with 86 | fixed block sizes or for carrying several RTP packets in a lower-layer 87 | protocol data unit. 88 | 89 | extension (X): 1 bit 90 | If the extension bit is set, the fixed header is followed by exactly 91 | one header extension, with a format defined in Section 5.3.1. 92 | 93 | CSRC count (CC): 4 bits 94 | The CSRC count contains the number of CSRC identifiers that follow the 95 | fixed header. 96 | 97 | marker (M): 1 bit 98 | The interpretation of the marker is defined by a profile. It is 99 | intended to allow significant events such as frame boundaries to be 100 | marked in the packet stream. A profile may define additional marker 101 | bits or specify that there is no marker bit by changing the number of 102 | bits in the payload type field (see Section 5.3). 103 | 104 | payload type (PT): 7 bits 105 | This field identifies the format of the RTP payload and determines its 106 | interpretation by the application. A profile specifies a default 107 | static mapping of payload type codes to payload formats. Additional 108 | payload type codes may be defined dynamically through non-RTP means 109 | (see Section 3). An initial set of default mappings for audio and 110 | video is specified in the companion profile Internet-Draft 111 | draft-ietf-avt-profile, and may be extended in future editions of the 112 | Assigned Numbers RFC [6]. An RTP sender emits a single RTP payload 113 | type at any given time; this field is not intended for multiplexing 114 | separate media streams (see Section 5.2). 115 | 116 | sequence number: 16 bits 117 | The sequence number increments by one for each RTP data packet sent, 118 | and may be used by the receiver to detect packet loss and to restore 119 | packet sequence. The initial value of the sequence number is random 120 | (unpredictable) to make known-plaintext attacks on encryption more 121 | difficult, even if the source itself does not encrypt, because the 122 | packets may flow through a translator that does. Techniques for 123 | choosing unpredictable numbers are discussed in [7]. 124 | 125 | timestamp: 32 bits 126 | The timestamp reflects the sampling instant of the first octet in the 127 | RTP data packet. The sampling instant must be derived from a clock 128 | that increments monotonically and linearly in time to allow 129 | synchronization and jitter calculations (see Section 6.3.1). The 130 | resolution of the clock must be sufficient for the desired 131 | synchronization accuracy and for measuring packet arrival jitter (one 132 | tick per video frame is typically not sufficient). The clock frequency 133 | is dependent on the format of data carried as payload and is specified 134 | statically in the profile or payload format specification that defines 135 | the format, or may be specified dynamically for payload formats 136 | defined through non-RTP means. If RTP packets are generated 137 | periodically, the nominal sampling instant as determined from the 138 | sampling clock is to be used, not a reading of the system clock. As an 139 | example, for fixed-rate audio the timestamp clock would likely 140 | increment by one for each sampling period. If an audio application 141 | reads blocks covering 160 sampling periods from the input device, the 142 | timestamp would be increased by 160 for each such block, regardless of 143 | whether the block is transmitted in a packet or dropped as silent. 144 | The initial value of the timestamp is random, as for the sequence 145 | number. Several consecutive RTP packets may have equal timestamps if 146 | they are (logically) generated at once, e.g., belong to the same video 147 | frame. Consecutive RTP packets may contain timestamps that are not 148 | monotonic if the data is not transmitted in the order it was sampled, 149 | as in the case of MPEG interpolated video frames. (The sequence 150 | numbers of the packets as transmitted will still be monotonic.) 151 | 152 | SSRC: 32 bits 153 | The SSRC field identifies the synchronization source. This identifier 154 | is chosen randomly, with the intent that no two synchronization 155 | sources within the same RTP session will have the same SSRC 156 | identifier. An example algorithm for generating a random identifier is 157 | presented in Appendix A.6. Although the probability of multiple 158 | sources choosing the same identifier is low, all RTP implementations 159 | must be prepared to detect and resolve collisions. Section 8 describes 160 | the probability of collision along with a mechanism for resolving 161 | collisions and detecting RTP-level forwarding loops based on the 162 | uniqueness of the SSRC identifier. If a source changes its source 163 | transport address, it must also choose a new SSRC identifier to avoid 164 | being interpreted as a looped source. 165 | 166 | CSRC list: 0 to 15 items, 32 bits each 167 | The CSRC list identifies the contributing sources for the payload 168 | contained in this packet. The number of identifiers is given by the CC 169 | field. If there are more than 15 contributing sources, only 15 may be 170 | identified. CSRC identifiers are inserted by mixers, using the SSRC 171 | identifiers of contributing sources. For example, for audio packets 172 | the SSRC identifiers of all sources that were mixed together to create 173 | a packet are listed, allowing correct talker indication at the 174 | receiver. 175 | 176 | */ 177 | 178 | #endif // _RTP_PACKET_H_ 179 | -------------------------------------------------------------------------------- /src/rewrite.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Lindenbaum GmbH 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "rewrite.h" 19 | 20 | #include "rtp_packet.h" 21 | #include "rtcp_packet.h" 22 | 23 | //////////////////////////////////////////////////////////////////////////////// 24 | // 25 | // RTP REWRITE 26 | // 27 | // try to maintain smooth RTP sequence numbers by adding an offsets when a 28 | // sequence number drop of at least MIN_DELTA is detected. Replace SSRC 29 | // by the last two numbers of the IP address, followed by the port number 30 | // of the external UDP destination (a.k.a. SBC). 31 | // 32 | //////////////////////////////////////////////////////////////////////////////// 33 | 34 | #define MIN_DELTA 4 35 | 36 | struct set_SN_arg { 37 | uint16_t sn; 38 | }; 39 | 40 | static inline void *set_SN_function(struct table_entry *entry, void *arg) { 41 | struct set_SN_arg *a = arg; 42 | 43 | const uint16_t sn = a->sn; 44 | 45 | if(!entry->entry_used) { 46 | entry->entry_used = 1; 47 | } 48 | else { 49 | uint16_t last_sn = entry->last_sn; 50 | uint16_t expected = last_sn + 1; 51 | if(sn < expected) { 52 | uint16_t delta = expected - sn; 53 | if(delta >= MIN_DELTA) { 54 | entry->offset += delta; 55 | } 56 | } 57 | } 58 | 59 | entry->last_sn = sn; 60 | a->sn += entry->offset; 61 | 62 | return arg; 63 | } 64 | 65 | static inline void rewrite_rtp(struct udphdr *udp_header, __be16 index, struct table_entry *ent) { 66 | int32_t remaining = ntohs(udp_header->len); 67 | uint8_t *data = (uint8_t *)udp_header; 68 | if(remaining >= sizeof(struct udphdr)) { 69 | data += sizeof(struct udphdr); 70 | remaining -= sizeof(struct udphdr); 71 | if(ntohs(index) & 1) { // odd port -> RTCP packet 72 | return; 73 | } 74 | else { // even port -> RTP PACKET 75 | if(remaining >= sizeof(struct rtp_packet)) { 76 | struct rtp_packet *packet = (struct rtp_packet *)data; 77 | if(packet->V == 2) { 78 | struct set_SN_arg a = { .sn = ntohs(packet->SN), }; 79 | table_atomically(index, set_SN_function, &a); 80 | packet->SN = htons(a.sn); 81 | } 82 | } 83 | } 84 | } 85 | } 86 | 87 | //////////////////////////////////////////////////////////////////////////////// 88 | // 89 | // MATCHING LOGIC 90 | // 91 | // if a packet comes from src_addr:src_port to dst_addr:dst_port, 92 | // then rewrite the packet so that it appears to come from src1_addr:src1_port 93 | // and goes to dst1_addr:dst1_port. If an address or port is ______________ (0), 94 | // then it always matches. 95 | // 96 | //////////////////////////////////////////////////////////////////////////////// 97 | 98 | static inline int match_udp_packet(struct iphdr *ip_header, struct udphdr *udp_header, 99 | __be32 src_addr, __be16 src_port, __be32 dst_addr, __be16 dst_port) { 100 | if((!src_addr || S_ADDR == src_addr) && 101 | (!src_port || S_PORT == src_port) && 102 | (!dst_addr || D_ADDR == dst_addr) && 103 | (!dst_port || D_PORT == dst_port)) { 104 | int match = 5; 105 | if(!src_addr) match--; 106 | if(!src_port) match--; 107 | if(!dst_addr) match--; 108 | if(!dst_port) match--; 109 | return match; 110 | } 111 | else { 112 | return 0; 113 | } 114 | } 115 | 116 | //////////////////////////////////////////////////////////////////////////////// 117 | // 118 | // REWRITE LOGIC 119 | // 120 | // Addresses do not get rewritten if the target address is ______________ (0), 121 | // likewise for ports. 122 | // 123 | //////////////////////////////////////////////////////////////////////////////// 124 | 125 | static inline void rewrite_udp_packet(struct iphdr *ip_header, struct udphdr *udp_header, 126 | __be32 src_addr, __be16 src_port, __be32 dst_addr, __be16 dst_port) { 127 | debug_print_tuple(" BEFORE REWRITE :", S_ADDR, S_PORT, D_ADDR, D_PORT); 128 | if(src_addr) S_ADDR = src_addr; 129 | if(src_port) S_PORT = src_port; 130 | if(dst_addr) D_ADDR = dst_addr; 131 | if(dst_port) D_PORT = dst_port; 132 | debug_print_tuple(" AFTER REWRITE :", S_ADDR, S_PORT, D_ADDR, D_PORT); 133 | } 134 | 135 | //////////////////////////////////////////////////////////////////////////////// 136 | // 137 | // ROUTING LOGIC 138 | // 139 | // The general idea is as follows: If a packet hits the proxy port, then the 140 | // direction the packet comes from is analyzed. Packets from the sender get 141 | // redirected to the sbc, and packets from the sbc get redirected to the 142 | // receiver. 143 | // In the pre routing step, only the destination address of the packet is 144 | // altered, so a routing decision can be made. The reason for leaving the 145 | // destination port unaltered in this step is that we still need the original 146 | // port to determine the complete route in the post routing step. 147 | // In the post routing step, the source address and the source and destination 148 | // ports are altered to complete the routing. 149 | // 150 | //////////////////////////////////////////////////////////////////////////////// 151 | 152 | // shorter names for routing field selection 153 | #define I_SRC_ADDR rt->i_src_addr 154 | #define I_SRC_PORT rt->i_src_port 155 | #define I_DST_ADDR rt->i_dst_addr 156 | #define I_DST_PORT rt->i_dst_port 157 | 158 | #define I_PRX_ADDR rt->i_prx_addr 159 | #define I_PRX_PORT rt->i_prx_port 160 | #define E_PRX_ADDR rt->e_prx_addr 161 | #define E_PRX_PORT rt->e_prx_port 162 | 163 | #define E_SRC_ADDR rt->e_src_addr 164 | #define E_SRC_PORT rt->e_src_port 165 | #define E_DST_ADDR rt->e_dst_addr 166 | #define E_DST_PORT rt->e_dst_port 167 | 168 | #define __________ 0 169 | 170 | enum { LOOPBACK_ROUTE, OUTGOING_ROUTE, INCOMING_ROUTE, AMBIGIUOS_ROUTE, NO_ROUTE, }; 171 | 172 | static inline int match_routes(struct iphdr *ip_header, struct udphdr *udp_header, 173 | struct routing *rt) { 174 | if(rt->loopback) { 175 | debug_printk(BANNER "LOOPBACK_ROUTE\n"); 176 | return LOOPBACK_ROUTE; 177 | } 178 | else { 179 | int outgoing_route_match = match_udp_packet(ip_header, udp_header, I_SRC_ADDR, I_SRC_PORT, __________, I_PRX_PORT); 180 | int incoming_route_match = match_udp_packet(ip_header, udp_header, E_SRC_ADDR, E_SRC_PORT, __________, E_PRX_PORT); 181 | if(outgoing_route_match > 0 || incoming_route_match > 0) { 182 | if(outgoing_route_match > incoming_route_match) { 183 | debug_printk(BANNER "OUTGOING_ROUTE\n"); 184 | return OUTGOING_ROUTE; 185 | } 186 | else if(incoming_route_match > outgoing_route_match) { 187 | debug_printk(BANNER "INCOMING_ROUTE\n"); 188 | return INCOMING_ROUTE; 189 | } 190 | else { 191 | debug_printk(BANNER "AMBIGIUOS_ROUTE\n"); 192 | return AMBIGIUOS_ROUTE; 193 | } 194 | } 195 | else { 196 | debug_printk(BANNER "NO_ROUTE\n"); 197 | return NO_ROUTE; 198 | } 199 | } 200 | } 201 | 202 | static inline unsigned int handle_incoming_udp_packet(struct iphdr *ip_header, struct udphdr *udp_header, 203 | struct routing *rt) { 204 | switch(match_routes(ip_header, udp_header, rt)) { 205 | case LOOPBACK_ROUTE: 206 | case OUTGOING_ROUTE: 207 | rewrite_udp_packet(ip_header, udp_header, __________, __________, E_DST_ADDR, __________); 208 | return NF_ACCEPT; 209 | case INCOMING_ROUTE: 210 | rewrite_udp_packet(ip_header, udp_header, __________, __________, I_DST_ADDR, __________); 211 | return NF_ACCEPT; 212 | case AMBIGIUOS_ROUTE: 213 | default: 214 | return NF_DROP; 215 | } 216 | } 217 | 218 | static unsigned int handle_outgoing_udp_packet(struct iphdr *ip_header, struct udphdr *udp_header, 219 | struct table_entry *ent, struct routing *rt) { 220 | switch(match_routes(ip_header, udp_header, rt)) { 221 | case LOOPBACK_ROUTE: 222 | case OUTGOING_ROUTE: 223 | rewrite_udp_packet(ip_header, udp_header, E_PRX_ADDR, E_PRX_PORT, __________, E_DST_PORT); 224 | if(rt->smoothing){ 225 | rewrite_rtp(udp_header, E_PRX_PORT, ent); 226 | } 227 | return NF_ACCEPT; 228 | case INCOMING_ROUTE: 229 | rewrite_udp_packet(ip_header, udp_header, I_PRX_ADDR, I_PRX_PORT, __________, I_DST_PORT); 230 | return NF_ACCEPT; 231 | default: 232 | return NF_DROP; 233 | } 234 | } 235 | 236 | static unsigned int pre_route_udp_packet(struct iphdr *ip_header, struct udphdr *udp_header, 237 | struct table_entry *_ent, struct routing *rt) { 238 | return handle_incoming_udp_packet(ip_header, udp_header, rt); 239 | } 240 | 241 | static unsigned int local_in_udp_packet(struct iphdr *ip_header, struct udphdr *udp_header, 242 | struct table_entry *ent, struct routing *rt) { 243 | return handle_outgoing_udp_packet(ip_header, udp_header, ent, rt); 244 | } 245 | 246 | //static unsigned int forward_udp_packet(struct iphdr *ip_header, struct udphdr *udp_header, 247 | // struct table_entry *ent, struct routing *rt) { 248 | // return NF_ACCEPT; 249 | //} 250 | 251 | static unsigned int local_out_udp_packet(struct iphdr *ip_header, struct udphdr *udp_header, 252 | struct table_entry *_ent, struct routing *rt) { 253 | return handle_incoming_udp_packet(ip_header, udp_header, rt); 254 | } 255 | 256 | static unsigned int post_route_udp_packet(struct iphdr *ip_header, struct udphdr *udp_header, 257 | struct table_entry *ent, struct routing *rt) { 258 | return handle_outgoing_udp_packet(ip_header, udp_header, ent, rt); 259 | } 260 | 261 | static struct mangle_hook mangle_hook[] = 262 | { 263 | { .hooknum = NF_IP_PRE_ROUTING, .name = "PRE_ROUTING ", .fn = pre_route_udp_packet, .priority = NF_IP_PRI_FIRST, }, 264 | { .hooknum = NF_IP_LOCAL_IN, .name = "LOCAL_IN ", .fn = local_in_udp_packet, .priority = NF_IP_PRI_LAST, }, 265 | //{ .hooknum = NF_IP_FORWARD, .name = "FORWARD ", .fn = forward_udp_packet, .priority = NF_IP_PRI_FILTER, }, 266 | { .hooknum = NF_IP_LOCAL_OUT, .name = "LOCAL_OUT ", .fn = local_out_udp_packet, .priority = NF_IP_PRI_FIRST, }, 267 | { .hooknum = NF_IP_POST_ROUTING, .name = "POST_ROUTING", .fn = post_route_udp_packet, .priority = NF_IP_PRI_LAST, }, 268 | }; 269 | 270 | #define HOOK_COUNT (sizeof(mangle_hook) / sizeof(mangle_hook[0])) 271 | 272 | // required by mangle.c 273 | int get_mangle_hooks(struct mangle_hook **mangle_hooks) { 274 | if(mangle_hooks) { 275 | *mangle_hooks = mangle_hook; 276 | } 277 | return HOOK_COUNT; 278 | } 279 | -------------------------------------------------------------------------------- /src/checksum.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Lindenbaum GmbH 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "checksum.h" 19 | 20 | static inline bool can_hw_csum(struct sk_buff *skb) { 21 | return !skb->dev || skb->dev->features & (NETIF_F_IP_CSUM | NETIF_F_HW_CSUM); 22 | } 23 | 24 | static inline __wsum udp_csum_partial(struct udphdr *udp_header, __wsum csum) { 25 | return csum_partial(udp_header, ntohs(udp_header->len), csum); 26 | } 27 | 28 | static inline __sum16 udp_csum_pseudo_header_partial(struct iphdr *ip_header, struct udphdr *udp_header) { 29 | return ~csum_tcpudp_magic(S_ADDR, D_ADDR, 30 | ntohs(udp_header->len), IPPROTO_UDP, 31 | 0); 32 | } 33 | 34 | static inline __sum16 udp_csum_pseudo_header(struct iphdr *ip_header, struct udphdr *udp_header, __wsum csum) { 35 | __sum16 sum = csum_tcpudp_magic(S_ADDR, D_ADDR, 36 | ntohs(udp_header->len), IPPROTO_UDP, 37 | csum); 38 | if(!sum) { 39 | return CSUM_MANGLED_0; 40 | } 41 | else { 42 | return sum; 43 | } 44 | } 45 | 46 | static inline void verify_checksums(struct iphdr *ip_header, struct udphdr *udp_header) { 47 | { 48 | __sum16 ip_check = ip_fast_csum((unsigned char *)ip_header, ip_header->ihl); 49 | if(ip_check != 0) { 50 | printk(BANNER " !!! verify_checksums: ip_fast_csum check failed! expected:"CSUM_FMT" actual:"CSUM_FMT"\n", ntohs(0), ntohs(ip_check)); 51 | } 52 | } 53 | { 54 | if(udp_header->check) { 55 | __wsum csum = udp_csum_partial(udp_header, 0); 56 | __sum16 udp_check = ~udp_csum_pseudo_header(ip_header, udp_header, csum); 57 | if(udp_check != 0) { 58 | printk(BANNER " !!! verify_checksums: udp_csum_partial/udp_csum_pseudo_header check failed! expected:"CSUM_FMT" actual:"CSUM_FMT"\n", ntohs(0), ntohs(udp_check)); 59 | } 60 | } 61 | } 62 | } 63 | 64 | static inline void verify_checksums_partial(struct iphdr *ip_header, struct udphdr *udp_header) { 65 | { 66 | __sum16 ip_check = ip_fast_csum((unsigned char *)ip_header, ip_header->ihl); 67 | if(ip_check != 0) { 68 | printk(BANNER " !!! verify_checksums_partial: ip_fast_csum check failed! expected:"CSUM_FMT" actual:"CSUM_FMT"\n", ntohs(0), ntohs(ip_check)); 69 | } 70 | } 71 | { 72 | __sum16 udp_check = udp_csum_pseudo_header_partial(ip_header, udp_header); 73 | if(udp_check != udp_header->check) { 74 | printk(BANNER " !!! verify_checksums_partial: udp_csum_pseudo_header_partial check failed! expected:"CSUM_FMT" actual:"CSUM_FMT"\n", ntohs(udp_header->check), ntohs(udp_check)); 75 | } 76 | } 77 | } 78 | 79 | void handle_incoming_checksums(struct sk_buff *skb, struct iphdr *ip_header, struct udphdr *udp_header) { 80 | // A. Checksumming of received packets by device. 81 | switch(skb->ip_summed) { 82 | case CHECKSUM_NONE: 83 | // Device failed to checksum this packet e.g. due to lack of capabilities. 84 | // The packet contains full (though not verified) checksum in packet but 85 | // not in skb->csum. Thus, skb->csum is undefined in this case. 86 | verify_checksums(ip_header, udp_header); // FIXME actuallay check if checksum is okay 87 | //skb->ip_summed = CHECKSUM_UNNECESSARY; 88 | break; 89 | case CHECKSUM_UNNECESSARY: 90 | // The hardware you're dealing with doesn't calculate the full checksum 91 | // (as in CHECKSUM_COMPLETE), but it does parse headers and verify checksums 92 | // for specific protocols. For such packets it will set CHECKSUM_UNNECESSARY 93 | // if their checksums are okay. skb->csum is still undefined in this case 94 | // though. It is a bad option, but, unfortunately, nowadays most vendors do 95 | // this. Apparently with the secret goal to sell you new devices, when you 96 | // will add new protocol to your host, f.e. IPv6 8) 97 | // 98 | // CHECKSUM_UNNECESSARY is applicable to following protocols: 99 | // TCP: IPv6 and IPv4. 100 | // UDP: IPv4 and IPv6. A device may apply CHECKSUM_UNNECESSARY to a 101 | // zero UDP checksum for either IPv4 or IPv6, the networking stack 102 | // may perform further validation in this case. 103 | // GRE: only if the checksum is present in the header. 104 | // SCTP: indicates the CRC in SCTP header has been validated. 105 | // 106 | // skb->csum_level indicates the number of consecutive checksums found in 107 | // the packet minus one that have been verified as CHECKSUM_UNNECESSARY. 108 | // For instance if a device receives an IPv6->UDP->GRE->IPv4->TCP packet 109 | // and a device is able to verify the checksums for UDP (possibly zero), 110 | // GRE (checksum flag is set), and TCP-- skb->csum_level would be set to 111 | // two. If the device were only able to verify the UDP checksum and not 112 | // GRE, either because it doesn't support GRE checksum of because GRE 113 | // checksum is bad, skb->csum_level would be set to zero (TCP checksum is 114 | // not considered in this case). 115 | #ifdef DEBUG 116 | verify_checksums(ip_header, udp_header); 117 | #endif 118 | break; 119 | case CHECKSUM_COMPLETE: 120 | // This is the most generic way. The device supplied checksum of the _whole_ 121 | // packet as seen by netif_rx() and fills out in skb->csum. Meaning, the 122 | // hardware doesn't need to parse L3/L4 headers to implement this. 123 | // 124 | // Note: Even if device supports only some protocols, but is able to produce 125 | // skb->csum, it MUST use CHECKSUM_COMPLETE, not CHECKSUM_UNNECESSARY. 126 | debug_printk(BANNER " !!! WARNING(incoming): unsupported checksum type: %s\n", ip_summed_toString(skb->ip_summed)); 127 | #ifdef DEBUG 128 | verify_checksums(ip_header, udp_header); 129 | #endif 130 | skb->ip_summed = CHECKSUM_UNNECESSARY; 131 | break; 132 | case CHECKSUM_PARTIAL: 133 | // This is identical to the case for output below. This may occur on a packet 134 | // received directly from another Linux OS, e.g., a virtualized Linux kernel 135 | // on the same host. The packet can be treated in the same way as 136 | // CHECKSUM_UNNECESSARY, except that on output (i.e., forwarding) the 137 | // checksum must be filled in by the OS or the hardware. 138 | #ifdef DEBUG 139 | verify_checksums_partial(ip_header, udp_header); 140 | #endif 141 | break; 142 | default: 143 | break; 144 | } 145 | } 146 | 147 | static inline void calculate_ip_checksum(struct iphdr *ip_header) { 148 | #ifdef DEBUG 149 | __sum16 ip_check = ip_header->check; 150 | #endif 151 | 152 | ip_header->check = 0; 153 | ip_header->check = ip_fast_csum((unsigned char *)ip_header, ip_header->ihl); 154 | debug_printk(BANNER " ip csum: "CSUM_FMT" -> "CSUM_FMT"\n", ntohs(ip_check), ntohs(ip_header->check)); 155 | } 156 | 157 | static inline void calculate_pseudo_header_udp_checksum(struct iphdr *ip_header, struct udphdr *udp_header) { 158 | #ifdef DEBUG 159 | __sum16 udp_check = udp_header->check; 160 | #endif 161 | 162 | udp_header->check = udp_csum_pseudo_header_partial(ip_header, udp_header); 163 | debug_printk(BANNER " udp pseudo header csum: "CSUM_FMT" -> "CSUM_FMT"\n", ntohs(udp_check), ntohs(udp_header->check)); 164 | } 165 | 166 | static inline void calculate_udp_checksum_full(struct iphdr *ip_header, struct udphdr *udp_header) { 167 | #ifdef DEBUG 168 | __sum16 udp_check = udp_header->check; 169 | #endif 170 | 171 | __wsum csum = 0; 172 | udp_header->check = 0; 173 | csum = udp_csum_partial(udp_header, csum); 174 | udp_header->check = udp_csum_pseudo_header(ip_header, udp_header, csum); 175 | debug_printk(BANNER " udp csum: "CSUM_FMT" -> "CSUM_FMT"\n", ntohs(udp_check), ntohs(udp_header->check)); 176 | } 177 | 178 | static inline bool is_local_out(struct sk_buff *skb) { 179 | struct rtable *rt = skb_rtable(skb); 180 | return rt && rt->rt_flags & RTCF_LOCAL; 181 | } 182 | 183 | void handle_outgoing_checksums(struct sk_buff *skb, struct iphdr *ip_header, struct udphdr *udp_header) { 184 | // B. Checksumming on output. 185 | switch(skb->ip_summed) { 186 | case CHECKSUM_PARTIAL: 187 | // The device is required to checksum the packet as seen by hard_start_xmit() 188 | // from skb->csum_start up to the end, and to record/write the checksum at 189 | // offset skb->csum_start + skb->csum_offset. 190 | // 191 | // The device must show its capabilities in dev->features, set up at device 192 | // setup time, e.g. netdev_features.h: 193 | // 194 | // NETIF_F_HW_CSUM - It's a clever device, it's able to checksum everything. 195 | // NETIF_F_IP_CSUM - Device is dumb, it's able to checksum only TCP/UDP over 196 | // IPv4. Sigh. Vendors like this way for an unknown reason. 197 | // Though, see comment above about CHECKSUM_UNNECESSARY. 8) 198 | // NETIF_F_IPV6_CSUM - About as dumb as the last one but does IPv6 instead. 199 | // NETIF_F_... - Well, you get the picture. 200 | calculate_ip_checksum(ip_header); 201 | calculate_pseudo_header_udp_checksum(ip_header, udp_header); 202 | 203 | debug_print_skb(" keeping CHECKSUM_PARTIAL", skb, ip_header, udp_header); 204 | break; 205 | case CHECKSUM_NONE: 206 | // The skb was already checksummed by the protocol, or a checksum is not 207 | // required. 208 | case CHECKSUM_UNNECESSARY: 209 | // Normally, the device will do per protocol specific checksumming. Protocol 210 | // implementations that do not want the NIC to perform the checksum 211 | // calculation should use this flag in their outgoing skbs. 212 | // 213 | // NETIF_F_FCOE_CRC - This indicates that the device can do FCoE FC CRC 214 | // offload. Correspondingly, the FCoE protocol driver 215 | // stack should use CHECKSUM_UNNECESSARY. 216 | default: 217 | //debug_printk(BANNER " !!! WARNING(outgoing): unsupported checksum type: %s\n", ip_summed_toString(skb->ip_summed)); 218 | calculate_ip_checksum(ip_header); 219 | if(!is_local_out(skb) && can_hw_csum(skb)) { 220 | skb->ip_summed = CHECKSUM_PARTIAL; 221 | skb->csum_start = skb_transport_header(skb) - skb->head; 222 | skb->csum_offset = offsetof(struct udphdr, check); 223 | 224 | calculate_pseudo_header_udp_checksum(ip_header, udp_header); 225 | 226 | debug_print_skb(" going from CHECKSUM_UNNECESSARY to CHECKSUM_PARTIAL", skb, ip_header, udp_header); 227 | } 228 | else { 229 | calculate_udp_checksum_full(ip_header, udp_header); 230 | 231 | debug_print_skb(" keeping CHECKSUM_UNNECESSARY", skb, ip_header, udp_header); 232 | } 233 | break; 234 | } 235 | // Any questions? No questions, good. --ANK 236 | } 237 | -------------------------------------------------------------------------------- /tests/table_test.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Lindenbaum GmbH 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "tests.h" 19 | 20 | #include "../src/table.h" 21 | #include "../src/config.h" 22 | 23 | //////////////////////////////////////////////////////////////////////////////// 24 | // 25 | // helper functions 26 | // 27 | 28 | void dump_config(void) { 29 | struct config cfg; 30 | config_get(&cfg); 31 | uint8_t int_proxy_ip[4] = htoal(ntohl(cfg.int_proxy_addr)); 32 | uint8_t ext_proxy_ip[4] = htoal(ntohl(cfg.ext_proxy_addr)); 33 | uint8_t smoothing = cfg.smoothing; 34 | uint8_t loopback = cfg.loopback; 35 | printf("config:" " int_proxy_addr: "IP_FMT " ext_proxy_addr: "IP_FMT" smoothing: "U8_FMT" loopback: "U8_FMT"\n", 36 | int_proxy_ip[0], int_proxy_ip[1], int_proxy_ip[2], int_proxy_ip[3], 37 | ext_proxy_ip[0], ext_proxy_ip[1], ext_proxy_ip[2], ext_proxy_ip[3], 38 | smoothing, loopback); 39 | } 40 | 41 | static void set_config(uint8_t int_proxy_ip[4], uint8_t ext_proxy_ip[4]) { 42 | struct config cfg; 43 | config_get(&cfg); 44 | cfg.int_proxy_addr = htonl(atohl(int_proxy_ip)); 45 | cfg.ext_proxy_addr = htonl(atohl(ext_proxy_ip)); 46 | config_set(&cfg); 47 | } 48 | 49 | void dump_table(void) { 50 | struct config cfg; 51 | config_get(&cfg); 52 | int index; 53 | printf("TABLE\n"); 54 | for(index = 0; index < TABLE_SIZE; index++) { 55 | struct table_entry ent; 56 | bool contains_entry = table_get(index, &ent); 57 | if(contains_entry) { 58 | uint8_t int_proxy_ip[4] = htoal(ntohl(cfg.int_proxy_addr)); 59 | uint8_t ext_proxy_ip[4] = htoal(ntohl(cfg.ext_proxy_addr)); 60 | uint16_t proxy_port = ntohs(index); 61 | 62 | uint8_t sender_ip[4] = htoal(ntohl(ent.sender_addr)); 63 | uint16_t sender_port = ntohs(ent.sender_port); 64 | 65 | uint8_t receiver_ip[4] = htoal(ntohl(ent.receiver_addr)); 66 | uint16_t receiver_port = ntohs(ent.receiver_port); 67 | 68 | uint8_t sbc_ip[4] = htoal(ntohl(ent.sbc_addr)); 69 | uint16_t sbc_port = ntohs(ent.sbc_port); 70 | 71 | printf("=> ("IP_PORT_FMT" -> "IP_PORT_FMT") ~> ("IP_PORT_FMT" -> "IP_PORT_FMT")\n", 72 | sender_ip[0], sender_ip[1], sender_ip[2], sender_ip[3], sender_port, 73 | int_proxy_ip[0], int_proxy_ip[1], int_proxy_ip[2], int_proxy_ip[3], proxy_port, 74 | ext_proxy_ip[0], ext_proxy_ip[1], ext_proxy_ip[2], ext_proxy_ip[3], proxy_port, 75 | sbc_ip[0], sbc_ip[1], sbc_ip[2], sbc_ip[3], sbc_port); 76 | printf(" < ("IP_PORT_FMT" -> "IP_PORT_FMT") ~> ("IP_PORT_FMT" -> "IP_PORT_FMT")\n", 77 | sbc_ip[0], sbc_ip[1], sbc_ip[2], sbc_ip[3], sbc_port, 78 | ext_proxy_ip[0], ext_proxy_ip[1], ext_proxy_ip[2], ext_proxy_ip[3], proxy_port, 79 | int_proxy_ip[0], int_proxy_ip[1], int_proxy_ip[2], int_proxy_ip[3], proxy_port, 80 | receiver_ip[0], receiver_ip[1], receiver_ip[2], receiver_ip[3], receiver_port); 81 | } 82 | } 83 | } 84 | 85 | void dump_routing(struct routing *rt) { 86 | uint8_t i_src_addr[4] = htoal(ntohl(rt->i_src_addr)); 87 | uint16_t i_src_port = ntohs(rt->i_src_port); 88 | uint8_t i_dst_addr[4] = htoal(ntohl(rt->i_dst_addr)); 89 | uint16_t i_dst_port = ntohs(rt->i_dst_port); 90 | uint8_t i_prx_addr[4] = htoal(ntohl(rt->i_prx_addr)); 91 | uint16_t i_prx_port = ntohs(rt->i_prx_port); 92 | uint8_t e_prx_addr[4] = htoal(ntohl(rt->e_prx_addr)); 93 | uint16_t e_prx_port = ntohs(rt->e_prx_port); 94 | uint8_t e_src_addr[4] = htoal(ntohl(rt->e_src_addr)); 95 | uint16_t e_src_port = ntohs(rt->e_src_port); 96 | uint8_t e_dst_addr[4] = htoal(ntohl(rt->e_dst_addr)); 97 | uint16_t e_dst_port = ntohs(rt->e_dst_port); 98 | 99 | if(rt->loopback) { 100 | printf(BANNER "ROUTING (loopback)\n"); 101 | } 102 | else { 103 | printf("ROUTING\n"); 104 | } 105 | printf("=> ("IP_PORT_FMT" -> "IP_PORT_FMT") ~> ("IP_PORT_FMT" -> "IP_PORT_FMT")\n", 106 | i_src_addr[0],i_src_addr[1],i_src_addr[2],i_src_addr[3],i_src_port, 107 | i_prx_addr[0],i_prx_addr[1],i_prx_addr[2],i_prx_addr[3],i_prx_port, 108 | e_prx_addr[0],e_prx_addr[1],e_prx_addr[2],e_prx_addr[3],e_prx_port, 109 | e_dst_addr[0],e_dst_addr[1],e_dst_addr[2],e_dst_addr[3],e_dst_port); 110 | printf(" < ("IP_PORT_FMT" -> "IP_PORT_FMT") ~> ("IP_PORT_FMT" -> "IP_PORT_FMT")\n", 111 | e_src_addr[0],e_src_addr[1],e_src_addr[2],e_src_addr[3],e_src_port, 112 | e_prx_addr[0],e_prx_addr[1],e_prx_addr[2],e_prx_addr[3],e_prx_port, 113 | i_prx_addr[0],i_prx_addr[1],i_prx_addr[2],i_prx_addr[3],i_prx_port, 114 | i_dst_addr[0],i_dst_addr[1],i_dst_addr[2],i_dst_addr[3],i_dst_port); 115 | } 116 | 117 | static void add_route(uint16_t prx_port, 118 | uint8_t snd_ip[4], uint16_t snd_port, 119 | uint8_t rcv_ip[4], uint16_t rcv_port, 120 | uint8_t sbc_ip[4], uint16_t sbc_port) { 121 | __be16 key = htons(prx_port); 122 | 123 | struct table_entry ent = { 124 | .sender_addr = htonl(atohl(snd_ip)), 125 | .sender_port = htons(snd_port), 126 | 127 | .receiver_addr = htonl(atohl(rcv_ip)), 128 | .receiver_port = htons(rcv_port), 129 | 130 | .sbc_addr = htonl(atohl(sbc_ip)), 131 | .sbc_port = htons(sbc_port), 132 | }; 133 | 134 | table_put(key, &ent); 135 | } 136 | 137 | static void assert_route(uint16_t prx_port, 138 | uint8_t snd_ip[4], uint16_t snd_port, 139 | uint8_t int_prx_ip[4], 140 | uint8_t ext_prx_ip[4], 141 | uint8_t sbc_ip[4], uint16_t sbc_port, 142 | uint8_t rcv_ip[4], uint16_t rcv_port, 143 | char *FILE, int LINE) { 144 | struct config cfg; 145 | config_get(&cfg); 146 | __be16 key = htons(prx_port); 147 | struct table_entry ent; 148 | if(table_get(key, &ent)) { 149 | 150 | assert_equals(atohl(snd_ip), ntohl(ent.sender_addr), FILE, LINE); 151 | assert_equals(snd_port, ntohs(ent.sender_port), FILE, LINE); 152 | 153 | assert_equals(atohl(int_prx_ip), ntohl(cfg.int_proxy_addr), FILE, LINE); 154 | assert_equals(atohl(ext_prx_ip), ntohl(cfg.ext_proxy_addr), FILE, LINE); 155 | 156 | assert_equals(atohl(sbc_ip), ntohl(ent.sbc_addr), FILE, LINE); 157 | assert_equals(sbc_port, ntohs(ent.sbc_port), FILE, LINE); 158 | 159 | assert_equals(atohl(rcv_ip), ntohl(ent.receiver_addr), FILE, LINE); 160 | assert_equals(rcv_port, ntohs(ent.receiver_port), FILE, LINE); 161 | 162 | return; 163 | } 164 | exit(-1); 165 | } 166 | 167 | static void assert_route_cascading(uint16_t prx_port, 168 | uint8_t src_1_ip[4], uint16_t src_1_port, 169 | uint8_t int_1_ip[4], uint16_t int_1_port, 170 | uint8_t ext_1_ip[4], uint16_t ext_1_port, 171 | uint8_t dst_1_ip[4], uint16_t dst_1_port, 172 | uint8_t src_2_ip[4], uint16_t src_2_port, 173 | uint8_t ext_2_ip[4], uint16_t ext_2_port, 174 | uint8_t int_2_ip[4], uint16_t int_2_port, 175 | uint8_t dst_2_ip[4], uint16_t dst_2_port, 176 | char *FILE, int LINE) { 177 | struct config cfg; 178 | config_get(&cfg); 179 | __be16 key = htons(prx_port); 180 | struct table_entry ent; 181 | struct routing rt; 182 | if(get_routing(key, &cfg, &ent, &rt)) { 183 | dump_routing(&rt); 184 | assert_equals(atohl(src_1_ip), ntohl(rt.i_src_addr), FILE, LINE); 185 | assert_equals( src_1_port, ntohs(rt.i_src_port), FILE, LINE); 186 | assert_equals(atohl(dst_2_ip), ntohl(rt.i_dst_addr), FILE, LINE); 187 | assert_equals( dst_2_port, ntohs(rt.i_dst_port), FILE, LINE); 188 | 189 | assert_equals(atohl(int_1_ip), ntohl(rt.i_prx_addr), FILE, LINE); 190 | assert_equals(atohl(int_2_ip), ntohl(rt.i_prx_addr), FILE, LINE); 191 | 192 | assert_equals( prx_port, ntohs(rt.i_prx_port), FILE, LINE); 193 | assert_equals( int_2_port, ntohs(rt.i_prx_port), FILE, LINE); 194 | 195 | assert_equals(atohl(ext_1_ip), ntohl(rt.e_prx_addr), FILE, LINE); 196 | assert_equals(atohl(ext_2_ip), ntohl(rt.e_prx_addr), FILE, LINE); 197 | 198 | assert_equals(atohl(src_2_ip), ntohl(rt.e_src_addr), FILE, LINE); 199 | assert_equals( src_2_port, ntohs(rt.e_src_port), FILE, LINE); 200 | assert_equals(atohl(dst_1_ip), ntohl(rt.e_dst_addr), FILE, LINE); 201 | assert_equals( dst_1_port, ntohs(rt.e_dst_port), FILE, LINE); 202 | 203 | return; 204 | } 205 | exit(-1); 206 | } 207 | 208 | 209 | //////////////////////////////////////////////////////////////////////////////// 210 | // 211 | // test functions 212 | // 213 | 214 | static void new_table_contains_no_entries_test(void) { 215 | struct config cfg; 216 | config_get(&cfg); 217 | int index; 218 | for(index = 0; index < TABLE_SIZE; index++) { 219 | struct table_entry ent; 220 | bool contains_entry = table_get(index, &ent); 221 | if(contains_entry) { 222 | printf(KRED"BUG"KNRM" %d %hu %hhu %hu %hhu %hu %hhu\n", index, 223 | ent.sender_addr, ent.sender_port, 224 | ent.receiver_addr, ent.receiver_port, 225 | ent.sbc_addr, ent.sbc_port); 226 | exit(-1); 227 | } 228 | } 229 | } 230 | 231 | #define SBC_IP {213, 30, 241, 190} 232 | #define PROXY_IP {10, 1, 40, 121} 233 | #define INT_PROXY_IP {1, 1, 1, 1} 234 | #define EXT_PROXY_IP {2, 2, 2, 2} 235 | #define MEDIA_IP {192, 168, 100, 8} 236 | 237 | static void cascade_test(void) { 238 | uint8_t int_ip[4] = PROXY_IP; 239 | uint8_t ext_ip[4] = PROXY_IP; 240 | 241 | set_config(int_ip, ext_ip); 242 | 243 | uint16_t prx_port_1 = 32768; 244 | uint16_t prx_port_2 = 32770; 245 | 246 | uint8_t snd_ip_1[4] = MEDIA_IP; 247 | uint16_t snd_port_1 = 18562; 248 | 249 | uint8_t rcv_ip_1[4] = MEDIA_IP; 250 | uint16_t rcv_port_1 = 18560; 251 | 252 | uint8_t sbc_ip_1[4] = PROXY_IP; 253 | uint16_t sbc_port_1 = prx_port_2; 254 | 255 | uint8_t snd_ip_2[4] = MEDIA_IP; 256 | uint16_t snd_port_2 = 18568; 257 | 258 | uint8_t rcv_ip_2[4] = MEDIA_IP; 259 | uint16_t rcv_port_2 = 18564; 260 | 261 | uint8_t sbc_ip_2[4] = PROXY_IP; 262 | uint16_t sbc_port_2 = prx_port_1; 263 | 264 | add_route(prx_port_1, 265 | snd_ip_1, snd_port_1, 266 | rcv_ip_1, rcv_port_1, 267 | sbc_ip_1, sbc_port_1); 268 | dump_config(); 269 | dump_table(); 270 | 271 | assert_route(prx_port_1, 272 | snd_ip_1, snd_port_1, 273 | int_ip, 274 | ext_ip, 275 | sbc_ip_1, sbc_port_1, 276 | rcv_ip_1, rcv_port_1, 277 | __FILE__, __LINE__); 278 | 279 | assert_route_cascading(prx_port_1, 280 | // from sender channel 281 | snd_ip_1, snd_port_1, 282 | int_ip, prx_port_1, 283 | ext_ip, prx_port_1, 284 | sbc_ip_1, sbc_port_1, 285 | // to receiver channel 286 | sbc_ip_1, sbc_port_1, 287 | ext_ip, prx_port_1, 288 | int_ip, prx_port_1, 289 | rcv_ip_1, rcv_port_1, 290 | // 291 | __FILE__, __LINE__); 292 | 293 | add_route(prx_port_2, 294 | snd_ip_2, snd_port_2, 295 | rcv_ip_2, rcv_port_2, 296 | sbc_ip_2, sbc_port_2); 297 | dump_table(); 298 | 299 | assert_route(prx_port_2, 300 | snd_ip_2, snd_port_2, 301 | int_ip, 302 | ext_ip, 303 | sbc_ip_2, sbc_port_2, 304 | rcv_ip_2, rcv_port_2, 305 | __FILE__, __LINE__); 306 | 307 | assert_route_cascading(prx_port_1, 308 | // from sender channel 309 | snd_ip_1, snd_port_1, 310 | int_ip, prx_port_1, 311 | int_ip, prx_port_2, 312 | rcv_ip_2, rcv_port_2, 313 | // to receiver channel 314 | snd_ip_2, snd_port_2, 315 | int_ip, prx_port_2, 316 | int_ip, prx_port_1, 317 | rcv_ip_1, rcv_port_1, 318 | // 319 | __FILE__, __LINE__); 320 | 321 | assert_route_cascading(prx_port_2, 322 | // from sender channel 323 | snd_ip_2, snd_port_2, 324 | int_ip, prx_port_2, 325 | int_ip, prx_port_1, 326 | rcv_ip_1, rcv_port_1, 327 | // to receiver channel 328 | snd_ip_1, snd_port_1, 329 | int_ip, prx_port_1, 330 | int_ip, prx_port_2, 331 | rcv_ip_2, rcv_port_2, 332 | // 333 | __FILE__, __LINE__); 334 | 335 | } 336 | 337 | static void short_circuiting_test(void) { 338 | uint8_t int_ip[4] = INT_PROXY_IP; 339 | uint8_t ext_ip[4] = EXT_PROXY_IP; 340 | 341 | set_config(int_ip, ext_ip); 342 | 343 | uint16_t prx_port = 32768; 344 | 345 | uint8_t snd_ip[4] = {0, 0, 0, 0}; 346 | uint16_t snd_port = 0; 347 | 348 | uint8_t rcv_ip[4] = INT_PROXY_IP; 349 | uint16_t rcv_port = prx_port; 350 | 351 | uint8_t sbc_ip[4] = SBC_IP; 352 | uint16_t sbc_port = 40960; 353 | 354 | add_route(prx_port, 355 | snd_ip, snd_port, 356 | rcv_ip, rcv_port, 357 | sbc_ip, sbc_port); 358 | 359 | dump_config(); 360 | dump_table(); 361 | 362 | struct config cfg; 363 | config_get(&cfg); 364 | __be16 key = htons(prx_port); 365 | struct table_entry ent; 366 | struct routing rt; 367 | if(get_routing(key, &cfg, &ent, &rt)) { 368 | dump_routing(&rt); 369 | } 370 | else { 371 | printf(KRED"BUG"KNRM" (no routing)\n"); 372 | exit(-1); 373 | } 374 | } 375 | 376 | //////////////////////////////////////////////////////////////////////////////// 377 | // 378 | // main function 379 | // 380 | 381 | int main(int argc, char **argv) { 382 | table_init(); 383 | 384 | config_init(); 385 | 386 | 387 | new_table_contains_no_entries_test(); 388 | 389 | printf("\n"); 390 | cascade_test(); 391 | 392 | printf("\n"); 393 | table_init(); 394 | new_table_contains_no_entries_test(); 395 | short_circuiting_test(); 396 | 397 | printf(KGRN"SUCCESS"KNRM"\n"); 398 | exit(0); 399 | } 400 | -------------------------------------------------------------------------------- /src/rtcp_packet.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Lindenbaum GmbH 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef _RTCP_PACKET_H_ 19 | #define _RTCP_PACKET_H_ 20 | 21 | #define SR_PACKET_TYPE 200 22 | #define RR_PACKET_TYPE 201 23 | #define SDES_PACKET_TYPE 202 24 | #define BYE_PACKET_TYPE 203 25 | #define APP_PACKET_TYPE 204 26 | 27 | struct rtcp_packet { 28 | #if defined(__BIG_ENDIAN_BITFIELD) 29 | uint8_t V:2; 30 | uint8_t P:1; 31 | uint8_t RC:5; 32 | #elif defined(__LITTLE_ENDIAN_BITFIELD) 33 | uint8_t RC:5; 34 | uint8_t P:1; 35 | uint8_t V:2; 36 | #else 37 | # error "this endianness is not supported" 38 | #endif 39 | uint8_t PT:8; 40 | 41 | __be16 length; 42 | 43 | __be32 SSRC; 44 | 45 | // ... 46 | }; 47 | 48 | /* 49 | struct sr_packet { 50 | struct rtcp_packet header; 51 | __be64 NTP_timestamp; 52 | __be32 RTP_timestamp; 53 | __be32 packet_count; 54 | __be32 octet_count; 55 | }; 56 | */ 57 | 58 | 59 | /* [RFC 1889] 60 | 61 | 6.1 RTCP Packet Format 62 | 63 | This specification defines several RTCP packet types to carry a 64 | variety of control information: 65 | 66 | SR 67 | Sender report, for transmission and reception statistics from 68 | participants that are active senders 69 | 70 | RR 71 | Receiver report, for reception statistics from participants that are 72 | not active senders 73 | 74 | SDES 75 | Source description items, including CNAME 76 | 77 | BYE 78 | Indicates end of participation 79 | 80 | APP 81 | Application specific functions 82 | 83 | Each RTCP packet begins with a fixed part similar to that of RTP data 84 | packets, followed by structured elements that may be of variable 85 | length according to the packet type but always end on a 32-bit 86 | boundary. The alignment requirement and a length field in the fixed 87 | part are included to make RTCP packets "stackable". Multiple RTCP 88 | packets may be concatenated without any intervening separators to form 89 | a compound RTCP packet that is sent in a single packet of the lower 90 | layer protocol, for example UDP. There is no explicit count of 91 | individual RTCP packets in the compound packet since the lower layer 92 | protocols are expected to provide an overall length to determine the 93 | end of the compound packet. 94 | 95 | Each individual RTCP packet in the compound packet may be processed 96 | independently with no requirements upon the order or combination of 97 | packets. However, in order to perform the functions of the protocol, 98 | the following constraints are imposed: 99 | 100 | Reception statistics (in SR or RR) should be sent as often as 101 | bandwidth constraints will allow to maximize the resolution of the 102 | statistics, therefore each periodically transmitted compound RTCP 103 | packet should include a report packet. New receivers need to receive 104 | the CNAME for a source as soon as possible to identify the source and 105 | to begin associating media for purposes such as lip-sync, so each 106 | compound RTCP packet should also include the SDES CNAME. The number 107 | of packet types that may appear first in the compound packet should be 108 | limited to increase the number of constant bits in the first word and 109 | the probability of successfully validating RTCP packets against 110 | misaddressed RTP data packets or other unrelated packets. Thus, all 111 | RTCP packets must be sent in a compound packet of at least two 112 | individual packets, with the following format recommended: 113 | 114 | Encryption prefix If and only if the compound packet is to be 115 | encrypted, it is prefixed by a random 32-bit quantity redrawn for 116 | every compound packet transmitted. SR or RR The first RTCP packet in 117 | the compound packet must always be a report packet to facilitate 118 | header validation as described in Appendix A.2. This is true even if 119 | no data has been sent nor received, in which case an empty RR is sent, 120 | and even if the only other RTCP packet in the compound packet is a 121 | BYE. Additional RRs If the number of sources for which reception 122 | statistics are being reported exceeds 31, the number that will fit 123 | into one SR or RR packet, then additional RR packets should follow the 124 | initial report packet. SDES An SDES packet containing a CNAME item 125 | must be included in each compound RTCP packet. Other source 126 | description items may optionally be included if required by a 127 | particular application, subject to bandwidth constraints (see Section 128 | 6.2.2). BYE or APP Other RTCP packet types, including those yet to be 129 | defined, may follow in any order, except that BYE should be the last 130 | packet sent with a given SSRC/CSRC. Packet types may appear more than 131 | once. It is advisable for translators and mixers to combine 132 | individual RTCP packets from the multiple sources they are forwarding 133 | into one compound packet whenever feasible in order to amortize the 134 | packet overhead (see Section 7). An example RTCP compound packet as 135 | might be produced by a mixer is shown in Fig. 1. If the overall length 136 | of a compound packet would exceed the maximum transmission unit (MTU) 137 | of the network path, it may be segmented into multiple shorter 138 | compound packets to be transmitted in separate packets of the 139 | underlying protocol. Note that each of the compound packets must begin 140 | with an SR or RR packet. 141 | 142 | An implementation may ignore incoming RTCP packets with types unknown 143 | to it. Additional RTCP packet types may be registered with the 144 | Internet Assigned Numbers Authority (IANA). 145 | 146 | if encrypted: random 32-bit integer 147 | | 148 | |[------- packet -------][----------- packet -----------][-packet-] 149 | | 150 | | receiver reports chunk chunk 151 | V item item item item 152 | -------------------------------------------------------------------- 153 | |R[SR|# sender #site#site][SDES|# CNAME PHONE |#CNAME LOC][BYE##why] 154 | |R[ |# report # 1 # 2 ][ |# |# ][ ## ] 155 | |R[ |# # # ][ |# |# ][ ## ] 156 | |R[ |# # # ][ |# |# ][ ## ] 157 | -------------------------------------------------------------------- 158 | |<------------------ UDP packet (compound packet) --------------->| 159 | 160 | 161 | #: SSRC/CSRC 162 | 163 | Figure 1: Example of an RTCP compound packet 164 | 165 | 166 | 6.3.1 SR: Sender report RTCP packet 167 | 168 | 0 1 2 3 169 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 170 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 171 | |V=2|P| RC | PT=SR=200 | length | header 172 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 173 | | SSRC of sender | 174 | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 175 | | NTP timestamp, most significant word | sender 176 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ info 177 | | NTP timestamp, least significant word | 178 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 179 | | RTP timestamp | 180 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 181 | | sender's packet count | 182 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 183 | | sender's octet count | 184 | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 185 | | SSRC_1 (SSRC of first source) | report 186 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block 187 | | fraction lost | cumulative number of packets lost | 1 188 | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 189 | | extended highest sequence number received | 190 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 191 | | interarrival jitter | 192 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 193 | | last SR (LSR) | 194 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 195 | | delay since last SR (DLSR) | 196 | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 197 | | SSRC_2 (SSRC of second source) | report 198 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block 199 | : ... : 2 200 | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 201 | | profile-specific extensions | 202 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 203 | 204 | The sender report packet consists of three sections, possibly followed 205 | by a fourth profile-specific extension section if defined. The first 206 | section, the header, is 8 octets long. The fields have the following 207 | meaning: 208 | 209 | version (V): 2 bits 210 | Identifies the version of RTP, which is the same in RTCP packets as in 211 | RTP data packets. The version defined by this specification is two 212 | (2). 213 | 214 | padding (P): 1 bit 215 | If the padding bit is set, this RTCP packet contains some additional 216 | padding octets at the end which are not part of the control 217 | information. The last octet of the padding is a count of how many 218 | padding octets should be ignored. Padding may be needed by some 219 | encryption algorithms with fixed block sizes. In a compound RTCP 220 | packet, padding should only be required on the last individual packet 221 | because the compound packet is encrypted as a whole. 222 | 223 | reception report count (RC): 5 bits The number of reception report 224 | blocks contained in this packet. A value of zero is valid. 225 | 226 | packet type (PT): 8 bits 227 | Contains the constant 200 to identify this as an RTCP SR packet. 228 | 229 | length: 16 bits 230 | The length of this RTCP packet in 32-bit words minus one, including 231 | the header and any padding. (The offset of one makes zero a valid 232 | length and avoids a possible infinite loop in scanning a compound RTCP 233 | packet, while counting 32-bit words avoids a validity check for a 234 | multiple of 4.) 235 | 236 | SSRC: 32 bits 237 | The synchronization source identifier for the originator of this SR 238 | packet. The second section, the sender information, is 20 octets long 239 | and is present in every sender report packet. It summarizes the data 240 | transmissions from this sender. The fields have the following meaning: 241 | 242 | NTP timestamp: 64 bits 243 | Indicates the wallclock time when this report was sent so that it may 244 | be used in combination with timestamps returned in reception reports 245 | from other receivers to measure round-trip propagation to those 246 | receivers. Receivers should expect that the measurement accuracy of 247 | the timestamp may be limited to far less than the resolution of the 248 | NTP timestamp. The measurement uncertainty of the timestamp is not 249 | indicated as it may not be known. A sender that can keep track of 250 | elapsed time but has no notion of wallclock time may use the elapsed 251 | time since joining the session instead. This is assumed to be less 252 | than 68 years, so the high bit will be zero. It is permissible to use 253 | the sampling clock to estimate elapsed wallclock time. A sender that 254 | has no notion of wallclock or elapsed time may set the NTP timestamp 255 | to zero. 256 | 257 | RTP timestamp: 32 bits 258 | Corresponds to the same time as the NTP timestamp (above), but in the 259 | same units and with the same random offset as the RTP timestamps in 260 | data packets. This correspondence may be used for intra- and 261 | inter-media synchronization for sources whose NTP timestamps are 262 | synchronized, and may be used by media- independent receivers to 263 | estimate the nominal RTP clock frequency. Note that in most cases this 264 | timestamp will not be equal to the RTP timestamp in any adjacent data 265 | packet. Rather, it is calculated from the corresponding NTP timestamp 266 | using the relationship between the RTP timestamp counter and real time 267 | as maintained by periodically checking the wallclock time at a 268 | sampling instant. 269 | 270 | sender's packet count: 32 bits 271 | The total number of RTP data packets transmitted by the sender since 272 | starting transmission up until the time this SR packet was 273 | generated. The count is reset if the sender changes its SSRC 274 | identifier. 275 | 276 | sender's octet count: 32 bits 277 | The total number of payload octets (i.e., not including header or 278 | padding) transmitted in RTP data packets by the sender since starting 279 | transmission up until the time this SR packet was generated. The count 280 | is reset if the sender changes its SSRC identifier. This field can be 281 | used to estimate the average payload data rate. The third section 282 | contains zero or more reception report blocks depending on the number 283 | of other sources heard by this sender since the last report. Each 284 | reception report block conveys statistics on the reception of RTP 285 | packets from a single synchronization source. Receivers do not carry 286 | over statistics when a source changes its SSRC identifier due to a 287 | collision. These statistics are: 288 | 289 | SSRC_n (source identifier): 32 bits 290 | The SSRC identifier of the source to which the information in this 291 | reception report block pertains. 292 | 293 | fraction lost: 8 bits 294 | The fraction of RTP data packets from source SSRC_n lost since the 295 | previous SR or RR packet was sent, expressed as a fixed point number 296 | with the binary point at the left edge of the field. (That is 297 | equivalent to taking the integer part after multiplying the loss 298 | fraction by 256.) This fraction is defined to be the number of packets 299 | lost divided by the number of packets expected, as defined in the next 300 | paragraph. An implementation is shown in Appendix A.3. If the loss is 301 | negative due to duplicates, the fraction lost is set to zero. Note 302 | that a receiver cannot tell whether any packets were lost after the 303 | last one received, and that there will be no reception report block 304 | issued for a source if all packets from that source sent during the 305 | last reporting interval have been lost. 306 | 307 | cumulative number of packets lost: 24 bits 308 | The total number of RTP data packets from source SSRC_n that have been 309 | lost since the beginning of reception. This number is defined to be 310 | the number of packets expected less the number of packets actually 311 | received, where the number of packets received includes any which are 312 | late or duplicates. Thus packets that arrive late are not counted as 313 | lost, and the loss may be negative if there are duplicates. The number 314 | of packets expected is defined to be the extended last sequence number 315 | received, as defined next, less the initial sequence number 316 | received. This may be calculated as shown in Appendix A.3. 317 | 318 | extended highest sequence number received: 32 bits 319 | The low 16 bits contain the highest sequence number received in an RTP 320 | data packet from source SSRC_n, and the most significant 16 bits 321 | extend that sequence number with the corresponding count of sequence 322 | number cycles, which may be maintained according to the algorithm in 323 | Appendix A.1. Note that different receivers within the same session 324 | will generate different extensions to the sequence number if their 325 | start times differ significantly. 326 | 327 | interarrival jitter: 32 bits 328 | An estimate of the statistical variance of the RTP data packet 329 | interarrival time, measured in timestamp units and expressed as an 330 | unsigned integer. The interarrival jitter J is defined to be the mean 331 | deviation (smoothed absolute value) of the difference D in packet 332 | spacing at the receiver compared to the sender for a pair of 333 | packets. As shown in the equation below, this is equivalent to the 334 | difference in the "relative transit time" for the two packets; the 335 | relative transit time is the difference between a packet's RTP 336 | timestamp and the receiver's clock at the time of arrival, measured in 337 | the same units. If Si is the RTP timestamp from packet i, and Ri is 338 | the time of arrival in RTP timestamp units for packet i, then for two 339 | packets i and j, D may be expressed as 340 | 341 | D(i,j)=(Rj-Ri)-(Sj-Si)=(Rj-Sj)-(Ri-Si) 342 | 343 | The interarrival jitter is calculated continuously as each data packet 344 | i is received from source SSRC_n, using this difference D for that 345 | packet and the previous packet i-1 in order of arrival (not 346 | necessarily in sequence), according to the formula 347 | 348 | J=J+(|D(i-1,i)|-J)/16 349 | 350 | Whenever a reception report is issued, the current value of J is 351 | sampled. 352 | 353 | The jitter calculation is prescribed here to allow profile- 354 | independent monitors to make valid interpretations of reports coming 355 | from different implementations. This algorithm is the optimal first- 356 | order estimator and the gain parameter 1/16 gives a good noise 357 | reduction ratio while maintaining a reasonable rate of convergence 358 | [11]. A sample implementation is shown in Appendix A.8. 359 | 360 | last SR timestamp (LSR): 32 bits 361 | The middle 32 bits out of 64 in the NTP timestamp (as explained in 362 | Section 4) received as part of the most recent RTCP sender report (SR) 363 | packet from source SSRC_n. If no SR has been received yet, the field 364 | is set to zero. 365 | 366 | delay since last SR (DLSR): 32 bits 367 | The delay, expressed in units of 1/65536 seconds, between receiving 368 | the last SR packet from source SSRC_n and sending this reception 369 | report block. If no SR packet has been received yet from SSRC_n, the 370 | DLSR field is set to zero. Let SSRC_r denote the receiver issuing 371 | this receiver report. Source SSRC_n can compute the round propagation 372 | delay to SSRC_r by recording the time A when this reception report 373 | block is received. It calculates the total round-trip time A-LSR using 374 | the last SR timestamp (LSR) field, and then subtracting this field to 375 | leave the round-trip propagation delay as (A- LSR - DLSR). This is 376 | illustrated in Fig. 2. 377 | 378 | This may be used as an approximate measure of distance to cluster 379 | receivers, although some links have very asymmetric delays. 380 | 381 | 382 | 6.3.2 RR: Receiver report RTCP packet 383 | 384 | [10 Nov 1995 11:33:25.125] [10 Nov 1995 11:33:36.5] 385 | n SR(n) A=b710:8000 (46864.500 s) 386 | ----------------------------------------------------------------> 387 | v ^ 388 | ntp_sec =0xb44db705 v ^ dlsr=0x0005.4000 ( 5.250s) 389 | ntp_frac=0x20000000 v ^ lsr =0xb705:2000 (46853.125s) 390 | (3024992016.125 s) v ^ 391 | r v ^ RR(n) 392 | ----------------------------------------------------------------> 393 | |<-DLSR->| 394 | (5.250 s) 395 | 396 | A 0xb710:8000 (46864.500 s) 397 | DLSR -0x0005:4000 ( 5.250 s) 398 | LSR -0xb705:2000 (46853.125 s) 399 | ------------------------------- 400 | delay 0x 6:2000 ( 6.125 s) 401 | 402 | Figure 2: Example for round-trip time computation 403 | 404 | 0 1 2 3 405 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 406 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 407 | |V=2|P| RC | PT=RR=201 | length | header 408 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 409 | | SSRC of packet sender | 410 | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 411 | | SSRC_1 (SSRC of first source) | report 412 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block 413 | | fraction lost | cumulative number of packets lost | 1 414 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 415 | | extended highest sequence number received | 416 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 417 | | interarrival jitter | 418 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 419 | | last SR (LSR) | 420 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 421 | | delay since last SR (DLSR) | 422 | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 423 | | SSRC_2 (SSRC of second source) | report 424 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block 425 | : ... : 2 426 | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 427 | | profile-specific extensions | 428 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 429 | 430 | The format of the receiver report (RR) packet is the same as that of 431 | the SR packet except that the packet type field contains the constant 432 | 201 and the five words of sender information are omitted (these are 433 | the NTP and RTP timestamps and sender's packet and octet counts). The 434 | remaining fields have the same meaning as for the SR packet. 435 | 436 | An empty RR packet (RC = 0) is put at the head of a compound RTCP 437 | packet when there is no data transmission or reception to report. 438 | 439 | 440 | 6.4 SDES: Source description RTCP packet 441 | 442 | 0 1 2 3 443 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 444 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 445 | |V=2|P| SC | PT=SDES=202 | length | header 446 | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 447 | | SSRC/CSRC_1 | chunk 448 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1 449 | | SDES items | 450 | | ... | 451 | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 452 | | SSRC/CSRC_2 | chunk 453 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 2 454 | | SDES items | 455 | | ... | 456 | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 457 | 458 | The SDES packet is a three-level structure composed of a header and 459 | zero or more chunks, each of of which is composed of items describing 460 | the source identified in that chunk. The items are described 461 | individually in subsequent sections. 462 | 463 | version (V), padding (P), length: 464 | As described for the SR packet (see Section 6.3.1). 465 | 466 | packet type (PT): 8 bits 467 | Contains the constant 202 to identify this as an RTCP SDES packet. 468 | 469 | source count (SC): 5 bits 470 | The number of SSRC/CSRC chunks contained in this SDES packet. A value 471 | of zero is valid but useless. Each chunk consists of an SSRC/CSRC 472 | identifier followed by a list of zero or more items, which carry 473 | information about the SSRC/CSRC. Each chunk starts on a 32-bit 474 | boundary. Each item consists of an 8-bit type field, an 8-bit octet 475 | count describing the length of the text (thus, not including this 476 | two-octet header), and the text itself. Note that the text can be no 477 | longer than 255 octets, but this is consistent with the need to limit 478 | RTCP bandwidth consumption. 479 | 480 | The text is encoded according to the UTF-2 encoding specified in Annex 481 | F of ISO standard 10646 [12,13]. This encoding is also known as UTF-8 482 | or UTF-FSS. It is described in "File System Safe UCS Transformation 483 | Format (FSS_UTF)", X/Open Preliminary Specification, Document Number 484 | P316 and Unicode Technical Report #4. US-ASCII is a subset of this 485 | encoding and requires no additional encoding. The presence of 486 | multi-octet encodings is indicated by setting the most significant bit 487 | of a character to a value of one. 488 | 489 | Items are contiguous, i.e., items are not individually padded to a 490 | 32-bit boundary. Text is not null terminated because some multi-octet 491 | encodings include null octets. The list of items in each chunk is 492 | terminated by one or more null octets, the first of which is 493 | interpreted as an item type of zero to denote the end of the list, and 494 | the remainder as needed to pad until the next 32-bit boundary. A chunk 495 | with zero items (four null octets) is valid but useless. 496 | 497 | End systems send one SDES packet containing their own source 498 | identifier (the same as the SSRC in the fixed RTP header). A mixer 499 | sends one SDES packet containing a chunk for each contributing source 500 | from which it is receiving SDES information, or multiple complete SDES 501 | packets in the format above if there are more than 31 such sources 502 | (see Section 7). 503 | 504 | The SDES items currently defined are described in the next 505 | sections. Only the CNAME item is mandatory. Some items shown here may 506 | be useful only for particular profiles, but the item types are all 507 | assigned from one common space to promote shared use and to simplify 508 | profile- independent applications. Additional items may be defined in 509 | a profile by registering the type numbers with IANA. 510 | 511 | 6.5 BYE: Goodbye RTCP packet 512 | 513 | 0 1 2 3 514 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 515 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 516 | |V=2|P| SC | PT=BYE=203 | length | 517 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 518 | | SSRC/CSRC | 519 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 520 | : ... : 521 | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 522 | | length | reason for leaving ... (opt) 523 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 524 | 525 | The BYE packet indicates that one or more sources are no longer 526 | active. 527 | 528 | version (V), padding (P), length: 529 | As described for the SR packet (see Section 6.3.1). 530 | 531 | packet type (PT): 8 bits 532 | Contains the constant 203 to identify this as an RTCP BYE packet. 533 | 534 | source count (SC): 5 bits 535 | The number of SSRC/CSRC identifiers included in this BYE packet. A 536 | count value of zero is valid, but useless. If a BYE packet is 537 | received by a mixer, the mixer forwards the BYE packet with the 538 | SSRC/CSRC identifier(s) unchanged. If a mixer shuts down, it should 539 | send a BYE packet listing all contributing sources it handles, as well 540 | as its own SSRC identifier. Optionally, the BYE packet may include an 541 | 8-bit octet count followed by that many octets of text indicating the 542 | reason for leaving, e.g., "camera malfunction" or "RTP loop 543 | detected". The string has the same encoding as that described for 544 | SDES. If the string fills the packet to the next 32-bit boundary, the 545 | string is not null terminated. If not, the BYE packet is padded with 546 | null octets. 547 | 548 | 6.6 APP: Application-defined RTCP packet 549 | 550 | 0 1 2 3 551 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 552 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 553 | |V=2|P| subtype | PT=APP=204 | length | 554 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 555 | | SSRC/CSRC | 556 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 557 | | name (ASCII) | 558 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 559 | | application-dependent data ... 560 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 561 | 562 | The APP packet is intended for experimental use as new applications 563 | and new features are developed, without requiring packet type value 564 | registration. APP packets with unrecognized names should be 565 | ignored. After testing and if wider use is justified, it is 566 | recommended that each APP packet be redefined without the subtype and 567 | name fields and registered with the Internet Assigned Numbers 568 | Authority using an RTCP packet type. 569 | 570 | version (V), padding (P), length: 571 | As described for the SR packet (see Section 6.3.1). 572 | 573 | subtype: 5 bits 574 | May be used as a subtype to allow a set of APP packets to be defined 575 | under one unique name, or for any application-dependent data. 576 | 577 | packet type (PT): 8 bits 578 | Contains the constant 204 to identify this as an RTCP APP packet. 579 | 580 | name: 4 octets 581 | A name chosen by the person defining the set of APP packets to be 582 | unique with respect to other APP packets this application might 583 | receive. The application creator might choose to use the application 584 | name, and then coordinate the allocation of subtype values to others 585 | who want to define new packet types for the 586 | application. Alternatively, it is recommended that others choose a 587 | name based on the entity they represent, then coordinate the use of 588 | the name within that entity. The name is interpreted as a sequence of 589 | four ASCII characters, with uppercase and lowercase characters treated 590 | as distinct. 591 | 592 | application-dependent data: variable length 593 | Application-dependent data may or may not appear in an APP packet. It 594 | is interpreted by the application and not RTP itself. It must be a 595 | multiple of 32 bits long. 596 | 597 | */ 598 | 599 | #endif // _RTCP_PACKET_H_ 600 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | --------------------------------------------------------------------------------