Branch data Line data Source code
1 : : #include <sys/socket.h>
2 : : #include <arpa/inet.h>
3 : : #include <unistd.h>
4 : : #include <string.h>
5 : : #include <wait.h>
6 : : #include <stdlib.h>
7 : :
8 : : #include "asm/types.h"
9 : : #include "util.h"
10 : : #include "list.h"
11 : : #include "files.h"
12 : : #include "netfilter.h"
13 : : #include "sockets.h"
14 : : #include "sk-inet.h"
15 : :
16 : : static char buf[512];
17 : :
18 : : /*
19 : : * Need to configure simple netfilter rules for blocking connections
20 : : * ANy brave soul to write it using xtables-devel?
21 : : */
22 : :
23 : : static const char *nf_conn_cmd = "%s -t filter %s %s --protocol tcp "
24 : : "--source %s --sport %d --destination %s --dport %d -j DROP";
25 : :
26 : : static char iptable_cmd_ipv4[] = "iptables";
27 : : static char iptable_cmd_ipv6[] = "ip6tables";
28 : :
29 : 96 : static int nf_connection_switch_raw(int family, u32 *src_addr, u16 src_port,
30 : : u32 *dst_addr, u16 dst_port,
31 : : bool input, bool lock)
32 : : {
33 : : char sip[INET_ADDR_LEN], dip[INET_ADDR_LEN];
34 : : char *cmd;
35 : 96 : char *argv[4] = { "sh", "-c", buf, NULL };
36 : : int ret;
37 : :
38 [ + - + ]: 96 : switch (family) {
39 : : case AF_INET:
40 : : cmd = iptable_cmd_ipv4;
41 : : break;
42 : : case AF_INET6:
43 : : cmd = iptable_cmd_ipv6;
44 : 32 : break;
45 : : default:
46 : 0 : pr_err("Unknown socket family %d\n", family);
47 : 0 : return -1;
48 : : };
49 : :
50 [ + - - + ]: 192 : if (!inet_ntop(family, (void *)src_addr, sip, INET_ADDR_LEN) ||
51 : 96 : !inet_ntop(family, (void *)dst_addr, dip, INET_ADDR_LEN)) {
52 : 0 : pr_perror("nf: Can't translate ip addr");
53 : 0 : return -1;
54 : : }
55 : :
56 [ + + ][ + + ]: 96 : snprintf(buf, sizeof(buf), nf_conn_cmd, cmd,
57 : : lock ? "-A" : "-D",
58 : : input ? "INPUT" : "OUTPUT",
59 : : dip, (int)dst_port, sip, (int)src_port);
60 : :
61 : 96 : pr_debug("\tRunning iptables [%s]\n", buf);
62 : :
63 : : /*
64 : : * cr_system is used here, because it blocks SIGCHLD before waiting
65 : : * a child and the child can't be waited from SIGCHLD handler.
66 : : */
67 : 96 : ret = cr_system(-1, -1, -1, "sh", argv);
68 [ + - ][ + - ]: 96 : if (ret < 0 || !WIFEXITED(ret) || WEXITSTATUS(ret)) {
[ - + ]
69 : 0 : pr_perror("Iptables configuration failed");
70 : 0 : return -1;
71 : : }
72 : :
73 [ + + ]: 96 : pr_info("%s %s:%d - %s:%d connection\n", lock ? "Locked" : "Unlocked",
74 : : sip, (int)src_port, dip, (int)dst_port);
75 : 96 : return 0;
76 : : }
77 : :
78 : 24 : static int nf_connection_switch(struct inet_sk_desc *sk, bool lock)
79 : : {
80 : : int ret = 0;
81 : :
82 : 24 : ret = nf_connection_switch_raw(sk->sd.family,
83 : 48 : sk->src_addr, sk->src_port,
84 : 48 : sk->dst_addr, sk->dst_port, true, lock);
85 [ + - ]: 24 : if (ret)
86 : : return -1;
87 : :
88 : 24 : ret = nf_connection_switch_raw(sk->sd.family,
89 : 24 : sk->dst_addr, sk->dst_port,
90 : 24 : sk->src_addr, sk->src_port, false, lock);
91 [ - + ]: 24 : if (ret) /* rollback */
92 : 0 : nf_connection_switch_raw(sk->sd.family,
93 : 0 : sk->src_addr, sk->src_port,
94 : 0 : sk->dst_addr, sk->dst_port, true, !lock);
95 : 24 : return ret;
96 : : }
97 : :
98 : 24 : int nf_lock_connection(struct inet_sk_desc *sk)
99 : : {
100 : 24 : return nf_connection_switch(sk, true);
101 : : }
102 : :
103 : 0 : int nf_unlock_connection(struct inet_sk_desc *sk)
104 : : {
105 : 0 : return nf_connection_switch(sk, false);
106 : : }
107 : :
108 : 24 : int nf_unlock_connection_info(struct inet_sk_info *si)
109 : : {
110 : : int ret = 0;
111 : :
112 : 24 : ret |= nf_connection_switch_raw(si->ie->family,
113 : 48 : si->ie->src_addr, si->ie->src_port,
114 : 48 : si->ie->dst_addr, si->ie->dst_port, true, false);
115 : 24 : ret |= nf_connection_switch_raw(si->ie->family,
116 : 48 : si->ie->dst_addr, si->ie->dst_port,
117 : 48 : si->ie->src_addr, si->ie->src_port, false, false);
118 : : /*
119 : : * rollback nothing in case of any error,
120 : : * because nobody checks errors of this function
121 : : */
122 : :
123 : 24 : return ret;
124 : : }
|