/* * (C) 2012 by Pablo Neira Ayuso * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This code has been sponsored by Sophos Astaro */ #include #include #include #include #include #include #include #include #include "expr_ops.h" #include "data_reg.h" #include "internal.h" static int nft_data_parse_cb(const struct nlattr *attr, void *data) { const struct nlattr **tb = data; int type = mnl_attr_get_type(attr); if (mnl_attr_type_valid(attr, NFTA_DATA_MAX) < 0) return MNL_CB_OK; switch(type) { case NFTA_DATA_VALUE: if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0) { perror("mnl_attr_validate"); return MNL_CB_ERROR; } break; case NFTA_DATA_VERDICT: if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) { perror("mnl_attr_validate"); return MNL_CB_ERROR; } break; } tb[type] = attr; return MNL_CB_OK; } static int nft_verdict_parse_cb(const struct nlattr *attr, void *data) { const struct nlattr **tb = data; int type = mnl_attr_get_type(attr); if (mnl_attr_type_valid(attr, NFTA_VERDICT_MAX) < 0) return MNL_CB_OK; switch(type) { case NFTA_VERDICT_CODE: if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { perror("mnl_attr_validate"); return MNL_CB_ERROR; } break; case NFTA_VERDICT_CHAIN: if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) { perror("mnl_attr_validate"); return MNL_CB_ERROR; } break; } tb[type] = attr; return MNL_CB_OK; } static int nft_parse_verdict(union nft_data_reg *data, const struct nlattr *attr, int *type) { struct nlattr *tb[NFTA_VERDICT_MAX+1]; if (mnl_attr_parse_nested(attr, nft_verdict_parse_cb, tb) < 0) { perror("mnl_attr_parse_nested"); return -1; } if (!tb[NFTA_VERDICT_CODE]) return -1; data->verdict = ntohl(mnl_attr_get_u32(tb[NFTA_VERDICT_CODE])); switch(data->verdict) { case NF_ACCEPT: case NF_DROP: case NF_QUEUE: case NFT_CONTINUE: case NFT_BREAK: case NFT_RETURN: if (type) *type = DATA_VERDICT; data->len = sizeof(data->verdict); break; case NFT_JUMP: case NFT_GOTO: if (!tb[NFTA_VERDICT_CHAIN]) return -1; data->chain = strdup(mnl_attr_get_str(tb[NFTA_VERDICT_CHAIN])); if (type) *type = DATA_CHAIN; break; default: return -1; } return 0; } static int __nft_parse_data(union nft_data_reg *data, const struct nlattr *attr) { void *orig = mnl_attr_get_payload(attr); size_t data_len = mnl_attr_get_payload_len(attr); if (data_len == 0) return -1; if (data_len > sizeof(uint32_t) * 4) return -1; memcpy(data->val, orig, data_len); data->len = data_len; return 0; } int nft_parse_data(union nft_data_reg *data, struct nlattr *attr, int *type) { struct nlattr *tb[NFTA_DATA_MAX+1] = {}; int ret = 0; if (mnl_attr_parse_nested(attr, nft_data_parse_cb, tb) < 0) { perror("mnl_attr_parse_nested"); return -1; } if (tb[NFTA_DATA_VALUE]) { if (type) *type = DATA_VALUE; ret = __nft_parse_data(data, tb[NFTA_DATA_VALUE]); if (ret < 0) return ret; } if (tb[NFTA_DATA_VERDICT]) ret = nft_parse_verdict(data, tb[NFTA_DATA_VERDICT], type); return ret; }