├── 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 |
--------------------------------------------------------------------------------