~ubuntu-branches/ubuntu/karmic/conntrack/karmic

« back to all changes in this revision

Viewing changes to src/netlink.c

  • Committer: Bazaar Package Importer
  • Author(s): Andres Rodriguez
  • Date: 2009-06-18 18:27:31 UTC
  • mfrom: (3.1.2 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090618182731-xlunt56xusrrif92
Tags: 1:0.9.12-1ubuntu1
* Merge from debian unstable (LP: #380358), remaining changes:
  - Error on fwrite failure in src/read_config_lex.c.
  - Patch from Kees Cook to not ignore return value of chdir call.
* debian/copyright: Updated download site.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 
19
19
#include "netlink.h"
20
20
#include "conntrackd.h"
21
 
#include "traffic_stats.h"
22
 
#include "ignore.h"
 
21
#include "filter.h"
23
22
#include "log.h"
24
 
#include "debug.h"
25
23
 
 
24
#include <string.h>
26
25
#include <errno.h>
27
 
 
28
 
int ignore_conntrack(struct nf_conntrack *ct)
29
 
{
30
 
        /* ignore a certain protocol */
31
 
        if (CONFIG(ignore_protocol)[nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)])
32
 
                return 1;
33
 
 
34
 
        /* Accept DNAT'ed traffic: not really coming to the local machine */
35
 
        if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) {
36
 
                debug_ct(ct, "DNAT");
37
 
                return 0;
38
 
        }
39
 
 
40
 
        /* Accept SNAT'ed traffic: not really coming to the local machine */
41
 
        if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) {
42
 
                debug_ct(ct, "SNAT");
43
 
                return 0;
44
 
        }
45
 
 
46
 
        /* Ignore traffic */
47
 
        if (ignore_pool_test(STATE(ignore_pool), ct)) {
48
 
                debug_ct(ct, "ignore traffic");
49
 
                return 1;
50
 
        }
51
 
 
52
 
        return 0;
53
 
}
54
 
 
55
 
static int event_handler(enum nf_conntrack_msg_type type,
56
 
                         struct nf_conntrack *ct,
57
 
                         void *data)
58
 
{
59
 
        /*
60
 
         * Ignore this conntrack: it talks about a
61
 
         * connection that is not interesting for us.
62
 
         */
63
 
        if (ignore_conntrack(ct))
64
 
                return NFCT_CB_STOP;
65
 
 
66
 
        switch(type) {
67
 
        case NFCT_T_NEW:
68
 
                STATE(mode)->event_new(ct);
69
 
                break;
70
 
        case NFCT_T_UPDATE:
71
 
                STATE(mode)->event_upd(ct);
72
 
                break;
73
 
        case NFCT_T_DESTROY:
74
 
                if (STATE(mode)->event_dst(ct))
75
 
                        update_traffic_stats(ct);
76
 
                break;
77
 
        default:
78
 
                dlog(LOG_WARNING, "unknown msg from ctnetlink\n");
79
 
                break;
80
 
        }
81
 
 
82
 
        return NFCT_CB_CONTINUE;
83
 
}
84
 
 
85
26
#include <sys/types.h>
86
27
#include <sys/socket.h>
87
28
#include <sys/fcntl.h>
 
29
#include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
88
30
 
89
 
int nl_init_event_handler(void)
 
31
struct nfct_handle *nl_init_event_handler(void)
90
32
{
91
 
        STATE(event) = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS);
92
 
        if (!STATE(event))
93
 
                return -1;
94
 
 
95
 
        fcntl(nfct_fd(STATE(event)), F_SETFL, O_NONBLOCK);
 
33
        struct nfct_handle *h;
 
34
 
 
35
        h = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS);
 
36
        if (h == NULL)
 
37
                return NULL;
 
38
 
 
39
        if (STATE(filter)) {
 
40
                if (CONFIG(filter_from_kernelspace)) {
 
41
                        if (nfct_filter_attach(nfct_fd(h),
 
42
                                               STATE(filter)) == -1) {
 
43
                                dlog(LOG_ERR, "cannot set event filtering: %s",
 
44
                                     strerror(errno));
 
45
                        }
 
46
                        dlog(LOG_NOTICE, "using kernel-space event filtering");
 
47
                } else
 
48
                        dlog(LOG_NOTICE, "using user-space event filtering");
 
49
 
 
50
                nfct_filter_destroy(STATE(filter));
 
51
        }
 
52
 
 
53
        fcntl(nfct_fd(h), F_SETFL, O_NONBLOCK);
96
54
 
97
55
        /* set up socket buffer size */
98
 
        if (CONFIG(netlink_buffer_size))
99
 
                nfnl_rcvbufsiz(nfct_nfnlh(STATE(event)),
100
 
                               CONFIG(netlink_buffer_size));
101
 
        else {
 
56
        if (CONFIG(netlink_buffer_size)) {
 
57
                CONFIG(netlink_buffer_size) = 
 
58
                    nfnl_rcvbufsiz(nfct_nfnlh(h), CONFIG(netlink_buffer_size));
 
59
        } else {
102
60
                socklen_t socklen = sizeof(unsigned int);
103
61
                unsigned int read_size;
104
62
 
105
63
                /* get current buffer size */
106
 
                getsockopt(nfct_fd(STATE(event)), SOL_SOCKET,
 
64
                getsockopt(nfct_fd(h), SOL_SOCKET,
107
65
                           SO_RCVBUF, &read_size, &socklen);
108
66
 
109
67
                CONFIG(netlink_buffer_size) = read_size;
110
68
        }
111
69
 
 
70
        dlog(LOG_NOTICE, "netlink event socket buffer size has been set "
 
71
                         "to %u bytes", CONFIG(netlink_buffer_size));
 
72
 
112
73
        /* ensure that maximum grown size is >= than maximum size */
113
74
        if (CONFIG(netlink_buffer_size_max_grown) < CONFIG(netlink_buffer_size))
114
75
                CONFIG(netlink_buffer_size_max_grown) =
115
76
                                        CONFIG(netlink_buffer_size);
116
77
 
117
 
        /* register callback for events */
118
 
        nfct_callback_register(STATE(event), NFCT_T_ALL, event_handler, NULL);
119
 
 
120
 
        return 0;
 
78
        return h;
121
79
}
122
80
 
123
 
static int dump_handler(enum nf_conntrack_msg_type type,
124
 
                        struct nf_conntrack *ct,
125
 
                        void *data)
 
81
struct nlif_handle *nl_init_interface_handler(void)
126
82
{
127
 
        /*
128
 
         * Ignore this conntrack: it talks about a
129
 
         * connection that is not interesting for us.
130
 
         */
131
 
        if (ignore_conntrack(ct))
132
 
                return NFCT_CB_CONTINUE;
 
83
        struct nlif_handle *h;
 
84
        h = nlif_open();
 
85
        if (h == NULL)
 
86
                return NULL;
133
87
 
134
 
        switch(type) {
135
 
        case NFCT_T_UPDATE:
136
 
                STATE(mode)->dump(ct);
137
 
                break;
138
 
        default:
139
 
                dlog(LOG_WARNING, "unknown msg from ctnetlink");
140
 
                break;
 
88
        if (nlif_query(h) == -1) {
 
89
                free(h);
 
90
                return NULL;
141
91
        }
142
 
        return NFCT_CB_CONTINUE;
143
 
}
144
 
 
145
 
int nl_init_dump_handler(void)
146
 
{
147
 
        /* open dump netlink socket */
148
 
        STATE(dump) = nfct_open(CONNTRACK, 0);
149
 
        if (!STATE(dump))
150
 
                return -1;
151
 
 
152
 
        /* register callback for dumped entries */
153
 
        nfct_callback_register(STATE(dump), NFCT_T_ALL, dump_handler, NULL);
154
 
 
155
 
        if (nl_dump_conntrack_table() == -1)
156
 
                return -1;
157
 
 
158
 
        return 0;
159
 
}
160
 
 
161
 
int nl_init_overrun_handler(void)
162
 
{
163
 
        STATE(overrun) = nfct_open(CONNTRACK, 0);
164
 
        if (!STATE(overrun))
165
 
                return -1;
166
 
 
167
 
        fcntl(nfct_fd(STATE(overrun)), F_SETFL, O_NONBLOCK);
168
 
 
169
 
        nfct_callback_register(STATE(overrun), 
170
 
                               NFCT_T_ALL, 
171
 
                               STATE(mode)->overrun, 
172
 
                               NULL);
173
 
        return 0;
 
92
        fcntl(nlif_fd(h), F_SETFL, O_NONBLOCK);
 
93
 
 
94
        return h;
174
95
}
175
96
 
176
97
static int warned = 0;
177
98
 
178
99
void nl_resize_socket_buffer(struct nfct_handle *h)
179
100
{
180
 
        unsigned int s = CONFIG(netlink_buffer_size) * 2;
 
101
        /* sock_setsockopt in net/core/sock.c doubles the size of the buffer */
 
102
        unsigned int s = CONFIG(netlink_buffer_size);
181
103
 
182
104
        /* already warned that we have reached the maximum buffer size */
183
105
        if (warned)
191
113
                     "unsynchronized replicas. Please, consider "
192
114
                     "increasing netlink socket buffer size via "
193
115
                     "SocketBufferSize and "
194
 
                     "SocketBufferSizeMaxGrown clauses in "
 
116
                     "SocketBufferSizeMaxGrowth clauses in "
195
117
                     "conntrackd.conf");
196
118
                s = CONFIG(netlink_buffer_size_max_grown);
197
119
                warned = 1;
200
122
        CONFIG(netlink_buffer_size) = nfnl_rcvbufsiz(nfct_nfnlh(h), s);
201
123
 
202
124
        /* notify the sysadmin */
203
 
        dlog(LOG_NOTICE, "netlink socket buffer size "
204
 
                         "has been set to %u bytes",
205
 
                         CONFIG(netlink_buffer_size));
206
 
}
207
 
 
208
 
int nl_dump_conntrack_table(void)
209
 
{
210
 
        return nfct_query(STATE(dump), NFCT_Q_DUMP, &CONFIG(family));
211
 
}
212
 
 
213
 
int nl_overrun_request_resync(void)
 
125
        dlog(LOG_NOTICE, "netlink socket buffer size has been increased "
 
126
                         "to %u bytes", CONFIG(netlink_buffer_size));
 
127
}
 
128
 
 
129
int nl_dump_conntrack_table(struct nfct_handle *h)
 
130
{
 
131
        return nfct_query(h, NFCT_Q_DUMP, &CONFIG(family));
 
132
}
 
133
 
 
134
int nl_flush_conntrack_table(struct nfct_handle *h)
 
135
{
 
136
        return nfct_query(h, NFCT_Q_FLUSH, &CONFIG(family));
 
137
}
 
138
 
 
139
int nl_send_resync(struct nfct_handle *h)
214
140
{
215
141
        int family = CONFIG(family);
216
 
        return nfct_send(STATE(overrun), NFCT_Q_DUMP, &family);
 
142
        return nfct_send(h, NFCT_Q_DUMP, &family);
217
143
}
218
144
 
219
 
int nl_exist_conntrack(struct nf_conntrack *ct)
 
145
/* if the handle has no callback, check for existence, otherwise, update */
 
146
int nl_get_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct)
220
147
{
221
148
        int ret;
222
 
 
223
 
        ret = nfct_query(STATE(dump), NFCT_Q_GET, ct);
 
149
        char __tmp[nfct_maxsize()];
 
150
        struct nf_conntrack *tmp = (struct nf_conntrack *) (void *)__tmp;
 
151
 
 
152
        memset(__tmp, 0, sizeof(__tmp));
 
153
 
 
154
        /* use the original tuple to check if it is there */
 
155
        nfct_copy(tmp, ct, NFCT_CP_ORIG);
 
156
 
 
157
        ret = nfct_query(h, NFCT_Q_GET, tmp);
224
158
        if (ret == -1)
225
159
                return errno == ENOENT ? 0 : -1;
226
160
 
227
161
        return 1;
228
162
}
229
163
 
230
 
/* This function modifies the conntrack passed as argument! */
231
 
int nl_create_conntrack(struct nf_conntrack *ct)
 
164
int nl_create_conntrack(struct nfct_handle *h, 
 
165
                        const struct nf_conntrack *orig,
 
166
                        int timeout)
232
167
{
233
 
        uint8_t flags;
234
 
 
235
 
        /* XXX: related connections */
 
168
        int ret;
 
169
        struct nf_conntrack *ct;
 
170
 
 
171
        ct = nfct_clone(orig);
 
172
        if (ct == NULL)
 
173
                return -1;
 
174
 
 
175
        if (timeout > 0)
 
176
                nfct_set_attr_u32(ct, ATTR_TIMEOUT, timeout);
 
177
 
 
178
        /* we hit error if we try to change the expected bit */
236
179
        if (nfct_attr_is_set(ct, ATTR_STATUS)) {
237
180
                uint32_t status = nfct_get_attr_u32(ct, ATTR_STATUS);
238
181
                status &= ~IPS_EXPECTED;
244
187
        /*
245
188
         * TCP flags to overpass window tracking for recovered connections
246
189
         */
247
 
        flags = IP_CT_TCP_FLAG_BE_LIBERAL | IP_CT_TCP_FLAG_SACK_PERM;
248
 
        nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_ORIG, flags);
249
 
        nfct_set_attr_u8(ct, ATTR_TCP_MASK_ORIG, flags);
250
 
        nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_REPL, flags);
251
 
        nfct_set_attr_u8(ct, ATTR_TCP_MASK_REPL, flags);
252
 
 
253
 
        return nfct_query(STATE(dump), NFCT_Q_CREATE_UPDATE, ct);
 
190
        if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) {
 
191
                uint8_t flags = IP_CT_TCP_FLAG_BE_LIBERAL |
 
192
                                IP_CT_TCP_FLAG_SACK_PERM;
 
193
 
 
194
                /* FIXME: workaround, we should send TCP flags in updates */
 
195
                if (nfct_get_attr_u8(ct, ATTR_TCP_STATE) >=
 
196
                                                TCP_CONNTRACK_TIME_WAIT) {
 
197
                        flags |= IP_CT_TCP_FLAG_CLOSE_INIT;
 
198
                }
 
199
                nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_ORIG, flags);
 
200
                nfct_set_attr_u8(ct, ATTR_TCP_MASK_ORIG, flags);
 
201
                nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_REPL, flags);
 
202
                nfct_set_attr_u8(ct, ATTR_TCP_MASK_REPL, flags);
 
203
        }
 
204
 
 
205
        ret = nfct_query(h, NFCT_Q_CREATE, ct);
 
206
        nfct_destroy(ct);
 
207
 
 
208
        return ret;
254
209
}
255
210
 
256
 
/* This function modifies the conntrack passed as argument! */
257
 
int nl_update_conntrack(struct nf_conntrack *ct)
 
211
int nl_update_conntrack(struct nfct_handle *h,
 
212
                        const struct nf_conntrack *orig,
 
213
                        int timeout)
258
214
{
 
215
        int ret;
 
216
        struct nf_conntrack *ct;
 
217
 
 
218
        ct = nfct_clone(orig);
 
219
        if (ct == NULL)
 
220
                return -1;
 
221
 
 
222
        if (timeout > 0)
 
223
                nfct_set_attr_u32(ct, ATTR_TIMEOUT, timeout);
 
224
 
259
225
        /* unset NAT info, otherwise we hit error */
260
226
        nfct_attr_unset(ct, ATTR_SNAT_IPV4);
261
227
        nfct_attr_unset(ct, ATTR_DNAT_IPV4);
267
233
                status &= ~IPS_NAT_MASK;
268
234
                nfct_set_attr_u32(ct, ATTR_STATUS, status);
269
235
        }
270
 
 
271
 
        return nl_create_conntrack(ct);
 
236
        /* we have to unset the helper to avoid EBUSY in reset timers */
 
237
        if (nfct_attr_is_set(ct, ATTR_HELPER_NAME))
 
238
                nfct_attr_unset(ct, ATTR_HELPER_NAME);
 
239
 
 
240
        /* we hit error if we try to update the master conntrack */
 
241
        if (ct_is_related(ct)) {
 
242
                nfct_attr_unset(ct, ATTR_MASTER_L3PROTO);
 
243
                nfct_attr_unset(ct, ATTR_MASTER_L4PROTO);
 
244
                nfct_attr_unset(ct, ATTR_MASTER_IPV4_SRC);
 
245
                nfct_attr_unset(ct, ATTR_MASTER_IPV4_DST);
 
246
                nfct_attr_unset(ct, ATTR_MASTER_IPV6_SRC);
 
247
                nfct_attr_unset(ct, ATTR_MASTER_IPV6_DST);
 
248
                nfct_attr_unset(ct, ATTR_MASTER_PORT_SRC);
 
249
                nfct_attr_unset(ct, ATTR_MASTER_PORT_DST);
 
250
        }
 
251
 
 
252
        /*
 
253
         * TCP flags to overpass window tracking for recovered connections
 
254
         */
 
255
        if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) {
 
256
                uint8_t flags = IP_CT_TCP_FLAG_BE_LIBERAL |
 
257
                                IP_CT_TCP_FLAG_SACK_PERM;
 
258
 
 
259
                /* FIXME: workaround, we should send TCP flags in updates */
 
260
                if (nfct_get_attr_u32(ct, ATTR_TCP_STATE) ==
 
261
                                                TCP_CONNTRACK_TIME_WAIT) {
 
262
                        flags |= IP_CT_TCP_FLAG_CLOSE_INIT;
 
263
                }
 
264
                nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_ORIG, flags);
 
265
                nfct_set_attr_u8(ct, ATTR_TCP_MASK_ORIG, flags);
 
266
                nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_REPL, flags);
 
267
                nfct_set_attr_u8(ct, ATTR_TCP_MASK_REPL, flags);
 
268
        }
 
269
 
 
270
        ret = nfct_query(h, NFCT_Q_UPDATE, ct);
 
271
        nfct_destroy(ct);
 
272
 
 
273
        return ret;
272
274
}
273
275
 
274
 
int nl_destroy_conntrack(struct nf_conntrack *ct)
 
276
int nl_destroy_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct)
275
277
{
276
 
        return nfct_query(STATE(dump), NFCT_Q_DESTROY, ct);
 
278
        return nfct_query(h, NFCT_Q_DESTROY, ct);
277
279
}