00001
00002
00003
00004
00005
00006
00007
00008 #include <stdlib.h>
00009 #include <string.h>
00010 #include <errno.h>
00011 #include <assert.h>
00012
00013 #include "internal/internal.h"
00014
00072 struct nf_conntrack *nfct_new(void)
00073 {
00074 struct nf_conntrack *ct;
00075
00076 ct = malloc(sizeof(struct nf_conntrack));
00077 if (!ct)
00078 return NULL;
00079
00080 memset(ct, 0, sizeof(struct nf_conntrack));
00081
00082 return ct;
00083 }
00084
00089 void nfct_destroy(struct nf_conntrack *ct)
00090 {
00091 assert(ct != NULL);
00092 if (ct->secctx)
00093 free(ct->secctx);
00094 free(ct);
00095 ct = NULL;
00096 }
00097
00102 size_t nfct_sizeof(const struct nf_conntrack *ct)
00103 {
00104 assert(ct != NULL);
00105 return sizeof(*ct);
00106 }
00107
00122 size_t nfct_maxsize(void)
00123 {
00124 return sizeof(struct nf_conntrack);
00125 }
00126
00134 struct nf_conntrack *nfct_clone(const struct nf_conntrack *ct)
00135 {
00136 struct nf_conntrack *clone;
00137
00138 assert(ct != NULL);
00139
00140 if ((clone = nfct_new()) == NULL)
00141 return NULL;
00142 memcpy(clone, ct, sizeof(*ct));
00143
00144 return clone;
00145 }
00146
00155 int nfct_setobjopt(struct nf_conntrack *ct, unsigned int option)
00156 {
00157 assert(ct != NULL);
00158
00159 if (unlikely(option > NFCT_SOPT_MAX)) {
00160 errno = EOPNOTSUPP;
00161 return -1;
00162 }
00163
00164 return __setobjopt(ct, option);
00165 }
00166
00175 int nfct_getobjopt(const struct nf_conntrack *ct, unsigned int option)
00176 {
00177 assert(ct != NULL);
00178
00179 if (unlikely(option > NFCT_GOPT_MAX)) {
00180 errno = EOPNOTSUPP;
00181 return -1;
00182 }
00183
00184 return __getobjopt(ct, option);
00185 }
00186
00210 int nfct_callback_register(struct nfct_handle *h,
00211 enum nf_conntrack_msg_type type,
00212 int (*cb)(enum nf_conntrack_msg_type type,
00213 struct nf_conntrack *ct,
00214 void *data),
00215 void *data)
00216 {
00217 struct __data_container *container;
00218
00219 assert(h != NULL);
00220
00221 container = malloc(sizeof(struct __data_container));
00222 if (!container)
00223 return -1;
00224 memset(container, 0, sizeof(struct __data_container));
00225
00226 h->cb = cb;
00227 container->h = h;
00228 container->type = type;
00229 container->data = data;
00230
00231 h->nfnl_cb_ct.call = __callback;
00232 h->nfnl_cb_ct.data = container;
00233 h->nfnl_cb_ct.attr_count = CTA_MAX;
00234
00235 nfnl_callback_register(h->nfnlssh_ct,
00236 IPCTNL_MSG_CT_NEW,
00237 &h->nfnl_cb_ct);
00238
00239 nfnl_callback_register(h->nfnlssh_ct,
00240 IPCTNL_MSG_CT_DELETE,
00241 &h->nfnl_cb_ct);
00242
00243 return 0;
00244 }
00245
00250 void nfct_callback_unregister(struct nfct_handle *h)
00251 {
00252 assert(h != NULL);
00253
00254 nfnl_callback_unregister(h->nfnlssh_ct, IPCTNL_MSG_CT_NEW);
00255 nfnl_callback_unregister(h->nfnlssh_ct, IPCTNL_MSG_CT_DELETE);
00256
00257 h->cb = NULL;
00258 free(h->nfnl_cb_ct.data);
00259
00260 h->nfnl_cb_ct.call = NULL;
00261 h->nfnl_cb_ct.data = NULL;
00262 h->nfnl_cb_ct.attr_count = 0;
00263 }
00264
00284 int nfct_callback_register2(struct nfct_handle *h,
00285 enum nf_conntrack_msg_type type,
00286 int (*cb)(const struct nlmsghdr *nlh,
00287 enum nf_conntrack_msg_type type,
00288 struct nf_conntrack *ct,
00289 void *data),
00290 void *data)
00291 {
00292 struct __data_container *container;
00293
00294 assert(h != NULL);
00295
00296 container = calloc(sizeof(struct __data_container), 1);
00297 if (container == NULL)
00298 return -1;
00299
00300 h->cb2 = cb;
00301 container->h = h;
00302 container->type = type;
00303 container->data = data;
00304
00305 h->nfnl_cb_ct.call = __callback;
00306 h->nfnl_cb_ct.data = container;
00307 h->nfnl_cb_ct.attr_count = CTA_MAX;
00308
00309 nfnl_callback_register(h->nfnlssh_ct,
00310 IPCTNL_MSG_CT_NEW,
00311 &h->nfnl_cb_ct);
00312
00313 nfnl_callback_register(h->nfnlssh_ct,
00314 IPCTNL_MSG_CT_DELETE,
00315 &h->nfnl_cb_ct);
00316
00317 return 0;
00318 }
00319
00324 void nfct_callback_unregister2(struct nfct_handle *h)
00325 {
00326 assert(h != NULL);
00327
00328 nfnl_callback_unregister(h->nfnlssh_ct, IPCTNL_MSG_CT_NEW);
00329 nfnl_callback_unregister(h->nfnlssh_ct, IPCTNL_MSG_CT_DELETE);
00330
00331 h->cb2 = NULL;
00332 free(h->nfnl_cb_ct.data);
00333
00334 h->nfnl_cb_ct.call = NULL;
00335 h->nfnl_cb_ct.data = NULL;
00336 h->nfnl_cb_ct.attr_count = 0;
00337 }
00338
00361 void nfct_set_attr(struct nf_conntrack *ct,
00362 const enum nf_conntrack_attr type,
00363 const void *value)
00364 {
00365 assert(ct != NULL);
00366 assert(value != NULL);
00367
00368 if (unlikely(type >= ATTR_MAX))
00369 return;
00370
00371 if (set_attr_array[type]) {
00372 set_attr_array[type](ct, value);
00373 set_bit(type, ct->set);
00374 }
00375 }
00376
00383 void nfct_set_attr_u8(struct nf_conntrack *ct,
00384 const enum nf_conntrack_attr type,
00385 u_int8_t value)
00386 {
00387 nfct_set_attr(ct, type, &value);
00388 }
00389
00396 void nfct_set_attr_u16(struct nf_conntrack *ct,
00397 const enum nf_conntrack_attr type,
00398 u_int16_t value)
00399 {
00400 nfct_set_attr(ct, type, &value);
00401 }
00402
00409 void nfct_set_attr_u32(struct nf_conntrack *ct,
00410 const enum nf_conntrack_attr type,
00411 u_int32_t value)
00412 {
00413 nfct_set_attr(ct, type, &value);
00414 }
00415
00422 void nfct_set_attr_u64(struct nf_conntrack *ct,
00423 const enum nf_conntrack_attr type,
00424 u_int64_t value)
00425 {
00426 nfct_set_attr(ct, type, &value);
00427 }
00428
00437 const void *nfct_get_attr(const struct nf_conntrack *ct,
00438 const enum nf_conntrack_attr type)
00439 {
00440 assert(ct != NULL);
00441
00442 if (unlikely(type >= ATTR_MAX)) {
00443 errno = EINVAL;
00444 return NULL;
00445 }
00446
00447 if (!test_bit(type, ct->set)) {
00448 errno = ENODATA;
00449 return NULL;
00450 }
00451
00452 assert(get_attr_array[type]);
00453
00454 return get_attr_array[type](ct);
00455 }
00456
00466 u_int8_t nfct_get_attr_u8(const struct nf_conntrack *ct,
00467 const enum nf_conntrack_attr type)
00468 {
00469 const u_int8_t *ret = nfct_get_attr(ct, type);
00470 return ret == NULL ? 0 : *ret;
00471 }
00472
00482 u_int16_t nfct_get_attr_u16(const struct nf_conntrack *ct,
00483 const enum nf_conntrack_attr type)
00484 {
00485 const u_int16_t *ret = nfct_get_attr(ct, type);
00486 return ret == NULL ? 0 : *ret;
00487 }
00488
00498 u_int32_t nfct_get_attr_u32(const struct nf_conntrack *ct,
00499 const enum nf_conntrack_attr type)
00500 {
00501 const u_int32_t *ret = nfct_get_attr(ct, type);
00502 return ret == NULL ? 0 : *ret;
00503 }
00504
00514 u_int64_t nfct_get_attr_u64(const struct nf_conntrack *ct,
00515 const enum nf_conntrack_attr type)
00516 {
00517 const u_int64_t *ret = nfct_get_attr(ct, type);
00518 return ret == NULL ? 0 : *ret;
00519 }
00520
00529 int nfct_attr_is_set(const struct nf_conntrack *ct,
00530 const enum nf_conntrack_attr type)
00531 {
00532 assert(ct != NULL);
00533
00534 if (unlikely(type >= ATTR_MAX)) {
00535 errno = EINVAL;
00536 return -1;
00537 }
00538 return test_bit(type, ct->set);
00539 }
00540
00550 int nfct_attr_is_set_array(const struct nf_conntrack *ct,
00551 const enum nf_conntrack_attr *type_array,
00552 int size)
00553 {
00554 int i;
00555
00556 assert(ct != NULL);
00557
00558 for (i=0; i<size; i++) {
00559 if (unlikely(type_array[i] >= ATTR_MAX)) {
00560 errno = EINVAL;
00561 return -1;
00562 }
00563 if (!test_bit(type_array[i], ct->set))
00564 return 0;
00565 }
00566 return 1;
00567 }
00568
00577 int nfct_attr_unset(struct nf_conntrack *ct,
00578 const enum nf_conntrack_attr type)
00579 {
00580 assert(ct != NULL);
00581
00582 if (unlikely(type >= ATTR_MAX)) {
00583 errno = EINVAL;
00584 return -1;
00585 }
00586 unset_bit(type, ct->set);
00587
00588 return 0;
00589 }
00590
00600 void nfct_set_attr_grp(struct nf_conntrack *ct,
00601 const enum nf_conntrack_attr_grp type,
00602 const void *data)
00603 {
00604 assert(ct != NULL);
00605
00606 if (unlikely(type >= ATTR_GRP_MAX))
00607 return;
00608
00609 if (set_attr_grp_array[type]) {
00610 set_attr_grp_array[type](ct, data);
00611 set_bitmask_u32(ct->set, attr_grp_bitmask[type], __NFCT_BITSET);
00612 }
00613 }
00614
00624 int nfct_get_attr_grp(const struct nf_conntrack *ct,
00625 const enum nf_conntrack_attr_grp type,
00626 void *data)
00627 {
00628 assert(ct != NULL);
00629
00630 if (unlikely(type >= ATTR_GRP_MAX)) {
00631 errno = EINVAL;
00632 return -1;
00633 }
00634 if (!test_bitmask_u32(ct->set, attr_grp_bitmask[type], __NFCT_BITSET)) {
00635 errno = ENODATA;
00636 return -1;
00637 }
00638 assert(get_attr_grp_array[type]);
00639 get_attr_grp_array[type](ct, data);
00640 return 0;
00641 }
00642
00650 int nfct_attr_grp_is_set(const struct nf_conntrack *ct,
00651 const enum nf_conntrack_attr_grp type)
00652 {
00653 assert(ct != NULL);
00654
00655 if (unlikely(type >= ATTR_GRP_MAX)) {
00656 errno = EINVAL;
00657 return -1;
00658 }
00659 return test_bitmask_u32(ct->set, attr_grp_bitmask[type], __NFCT_BITSET);
00660 }
00661
00670 int nfct_attr_grp_unset(struct nf_conntrack *ct,
00671 const enum nf_conntrack_attr_grp type)
00672 {
00673 assert(ct != NULL);
00674
00675 if (unlikely(type >= ATTR_GRP_MAX)) {
00676 errno = EINVAL;
00677 return -1;
00678 }
00679 unset_bitmask_u32(ct->set, attr_grp_bitmask[type], __NFCT_BITSET);
00680
00681 return 0;
00682 }
00683
00709 int nfct_build_conntrack(struct nfnl_subsys_handle *ssh,
00710 void *req,
00711 size_t size,
00712 u_int16_t type,
00713 u_int16_t flags,
00714 const struct nf_conntrack *ct)
00715 {
00716 assert(ssh != NULL);
00717 assert(req != NULL);
00718 assert(ct != NULL);
00719
00720 return __build_conntrack(ssh, req, size, type, flags, ct);
00721 }
00722
00757 int nfct_build_query(struct nfnl_subsys_handle *ssh,
00758 const enum nf_conntrack_query qt,
00759 const void *data,
00760 void *buffer,
00761 unsigned int size)
00762 {
00763 struct nfnlhdr *req = buffer;
00764 const u_int32_t *family = data;
00765
00766 assert(ssh != NULL);
00767 assert(data != NULL);
00768 assert(req != NULL);
00769
00770 memset(req, 0, size);
00771
00772 switch(qt) {
00773 case NFCT_Q_CREATE:
00774 nfct_build_conntrack(ssh, req, size, IPCTNL_MSG_CT_NEW, NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK|NLM_F_EXCL, data);
00775 break;
00776 case NFCT_Q_UPDATE:
00777 nfct_build_conntrack(ssh, req, size, IPCTNL_MSG_CT_NEW, NLM_F_REQUEST|NLM_F_ACK, data);
00778 break;
00779 case NFCT_Q_DESTROY:
00780 nfct_build_conntrack(ssh, req, size, IPCTNL_MSG_CT_DELETE, NLM_F_REQUEST|NLM_F_ACK, data);
00781 break;
00782 case NFCT_Q_GET:
00783 nfct_build_conntrack(ssh, req, size, IPCTNL_MSG_CT_GET, NLM_F_REQUEST|NLM_F_ACK, data);
00784 break;
00785 case NFCT_Q_FLUSH:
00786 nfnl_fill_hdr(ssh, &req->nlh, 0, *family, 0, IPCTNL_MSG_CT_DELETE, NLM_F_REQUEST|NLM_F_ACK);
00787 break;
00788 case NFCT_Q_DUMP:
00789 nfnl_fill_hdr(ssh, &req->nlh, 0, *family, 0, IPCTNL_MSG_CT_GET, NLM_F_REQUEST|NLM_F_DUMP);
00790 break;
00791 case NFCT_Q_DUMP_RESET:
00792 nfnl_fill_hdr(ssh, &req->nlh, 0, *family, 0, IPCTNL_MSG_CT_GET_CTRZERO, NLM_F_REQUEST|NLM_F_DUMP);
00793 break;
00794 case NFCT_Q_CREATE_UPDATE:
00795 nfct_build_conntrack(ssh, req, size, IPCTNL_MSG_CT_NEW, NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK, data);
00796 break;
00797
00798 default:
00799 errno = ENOTSUP;
00800 return -1;
00801 }
00802 return 1;
00803 }
00804
00829 int nfct_parse_conntrack(enum nf_conntrack_msg_type type,
00830 const struct nlmsghdr *nlh,
00831 struct nf_conntrack *ct)
00832 {
00833 unsigned int flags;
00834 int len = nlh->nlmsg_len;
00835 struct nfgenmsg *nfhdr = NLMSG_DATA(nlh);
00836 struct nfattr *cda[CTA_MAX];
00837
00838 assert(nlh != NULL);
00839 assert(ct != NULL);
00840
00841 len -= NLMSG_LENGTH(sizeof(struct nfgenmsg));
00842 if (len < 0) {
00843 errno = EINVAL;
00844 return NFCT_T_ERROR;
00845 }
00846
00847 flags = __parse_message_type(nlh);
00848 if (!(flags & type))
00849 return 0;
00850
00851 nfnl_parse_attr(cda, CTA_MAX, NFA_DATA(nfhdr), len);
00852
00853 __parse_conntrack(nlh, cda, ct);
00854
00855 return flags;
00856 }
00857
00876 int nfct_query(struct nfct_handle *h,
00877 const enum nf_conntrack_query qt,
00878 const void *data)
00879 {
00880 size_t size = 4096;
00881 union {
00882 char buffer[size];
00883 struct nfnlhdr req;
00884 } u;
00885
00886 assert(h != NULL);
00887 assert(data != NULL);
00888
00889 if (nfct_build_query(h->nfnlssh_ct, qt, data, &u.req, size) == -1)
00890 return -1;
00891
00892 return nfnl_query(h->nfnlh, &u.req.nlh);
00893 }
00894
00908 int nfct_send(struct nfct_handle *h,
00909 const enum nf_conntrack_query qt,
00910 const void *data)
00911 {
00912 size_t size = 4096;
00913 union {
00914 char buffer[size];
00915 struct nfnlhdr req;
00916 } u;
00917
00918 assert(h != NULL);
00919 assert(data != NULL);
00920
00921 if (nfct_build_query(h->nfnlssh_ct, qt, data, &u.req, size) == -1)
00922 return -1;
00923
00924 return nfnl_send(h->nfnlh, &u.req.nlh);
00925 }
00926
00927
00936 int nfct_catch(struct nfct_handle *h)
00937 {
00938 assert(h != NULL);
00939
00940 return nfnl_catch(h->nfnlh);
00941 }
00942
00979 int nfct_snprintf(char *buf,
00980 unsigned int size,
00981 const struct nf_conntrack *ct,
00982 unsigned int msg_type,
00983 unsigned int out_type,
00984 unsigned int flags)
00985 {
00986 assert(buf != NULL);
00987 assert(size > 0);
00988 assert(ct != NULL);
00989
00990 return __snprintf_conntrack(buf, size, ct, msg_type, out_type, flags);
00991 }
00992
01011 int nfct_compare(const struct nf_conntrack *ct1,
01012 const struct nf_conntrack *ct2)
01013 {
01014 assert(ct1 != NULL);
01015 assert(ct2 != NULL);
01016
01017 return __compare(ct1, ct2, NFCT_CMP_ALL);
01018 }
01019
01057 int nfct_cmp(const struct nf_conntrack *ct1,
01058 const struct nf_conntrack *ct2,
01059 unsigned int flags)
01060 {
01061 assert(ct1 != NULL);
01062 assert(ct2 != NULL);
01063
01064 return __compare(ct1, ct2, flags);
01065 }
01066
01089 void nfct_copy(struct nf_conntrack *ct1,
01090 const struct nf_conntrack *ct2,
01091 unsigned int flags)
01092 {
01093 int i;
01094
01095 assert(ct1 != NULL);
01096 assert(ct2 != NULL);
01097
01098 if (flags == NFCT_CP_ALL) {
01099 for (i=0; i<ATTR_MAX; i++) {
01100 if (test_bit(i, ct2->set)) {
01101 assert(copy_attr_array[i]);
01102 copy_attr_array[i](ct1, ct2);
01103 set_bit(i, ct1->set);
01104 }
01105 }
01106 return;
01107 }
01108
01109 static const int cp_orig_mask[] = {
01110 ATTR_ORIG_IPV4_SRC,
01111 ATTR_ORIG_IPV4_DST,
01112 ATTR_ORIG_IPV6_SRC,
01113 ATTR_ORIG_IPV6_DST,
01114 ATTR_ORIG_PORT_SRC,
01115 ATTR_ORIG_PORT_DST,
01116 ATTR_ICMP_TYPE,
01117 ATTR_ICMP_CODE,
01118 ATTR_ICMP_ID,
01119 ATTR_ORIG_L3PROTO,
01120 ATTR_ORIG_L4PROTO,
01121 };
01122 #define __CP_ORIG_MAX sizeof(cp_orig_mask)/sizeof(int)
01123
01124 if (flags & NFCT_CP_ORIG) {
01125 for (i=0; i<__CP_ORIG_MAX; i++) {
01126 if (test_bit(cp_orig_mask[i], ct2->set)) {
01127 assert(copy_attr_array[i]);
01128 copy_attr_array[cp_orig_mask[i]](ct1, ct2);
01129 set_bit(cp_orig_mask[i], ct1->set);
01130 }
01131 }
01132 }
01133
01134 static const int cp_repl_mask[] = {
01135 ATTR_REPL_IPV4_SRC,
01136 ATTR_REPL_IPV4_DST,
01137 ATTR_REPL_IPV6_SRC,
01138 ATTR_REPL_IPV6_DST,
01139 ATTR_REPL_PORT_SRC,
01140 ATTR_REPL_PORT_DST,
01141 ATTR_REPL_L3PROTO,
01142 ATTR_REPL_L4PROTO,
01143 };
01144 #define __CP_REPL_MAX sizeof(cp_repl_mask)/sizeof(int)
01145
01146 if (flags & NFCT_CP_REPL) {
01147 for (i=0; i<__CP_REPL_MAX; i++) {
01148 if (test_bit(cp_repl_mask[i], ct2->set)) {
01149 assert(copy_attr_array[i]);
01150 copy_attr_array[cp_repl_mask[i]](ct1, ct2);
01151 set_bit(cp_repl_mask[i], ct1->set);
01152 }
01153 }
01154 }
01155
01156 if (flags & NFCT_CP_META) {
01157 for (i=ATTR_TCP_STATE; i<ATTR_MAX; i++) {
01158 if (test_bit(i, ct2->set)) {
01159 assert(copy_attr_array[i]),
01160 copy_attr_array[i](ct1, ct2);
01161 set_bit(i, ct1->set);
01162 }
01163 }
01164 }
01165 }
01166
01175 void nfct_copy_attr(struct nf_conntrack *ct1,
01176 const struct nf_conntrack *ct2,
01177 const enum nf_conntrack_attr type)
01178 {
01179 if (test_bit(type, ct2->set)) {
01180 assert(copy_attr_array[type]);
01181 copy_attr_array[type](ct1, ct2);
01182 set_bit(type, ct1->set);
01183 }
01184 }
01185
01202 struct nfct_filter *nfct_filter_create(void)
01203 {
01204 return calloc(sizeof(struct nfct_filter), 1);
01205 }
01206
01215 void nfct_filter_destroy(struct nfct_filter *filter)
01216 {
01217 assert(filter != NULL);
01218 free(filter);
01219 filter = NULL;
01220 }
01221
01231 void nfct_filter_add_attr(struct nfct_filter *filter,
01232 const enum nfct_filter_attr type,
01233 const void *value)
01234 {
01235 assert(filter != NULL);
01236 assert(value != NULL);
01237
01238 if (unlikely(type >= NFCT_FILTER_MAX))
01239 return;
01240
01241 if (filter_attr_array[type]) {
01242 filter_attr_array[type](filter, value);
01243 set_bit(type, filter->set);
01244 }
01245 }
01246
01255 void nfct_filter_add_attr_u32(struct nfct_filter *filter,
01256 const enum nfct_filter_attr type,
01257 u_int32_t value)
01258 {
01259 nfct_filter_add_attr(filter, type, &value);
01260 }
01261
01277 int nfct_filter_set_logic(struct nfct_filter *filter,
01278 const enum nfct_filter_attr type,
01279 const enum nfct_filter_logic logic)
01280 {
01281 if (unlikely(type >= NFCT_FILTER_MAX)) {
01282 errno = ENOTSUP;
01283 return -1;
01284 }
01285
01286 if (filter->logic[type]) {
01287 errno = EBUSY;
01288 return -1;
01289 }
01290
01291 filter->logic[type] = logic;
01292
01293 return 0;
01294 }
01295
01305 int nfct_filter_attach(int fd, struct nfct_filter *filter)
01306 {
01307 assert(filter != NULL);
01308
01309 return __setup_netlink_socket_filter(fd, filter);
01310 }
01311
01318 int nfct_filter_detach(int fd)
01319 {
01320 int val = 0;
01321
01322 return setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, &val, sizeof(val));
01323 }
01324