@@ -10,6 +10,7 @@ enum nfnl_acct_msg_types {
NFNL_MSG_ACCT_GET,
NFNL_MSG_ACCT_GET_CTRZERO,
NFNL_MSG_ACCT_DEL,
+ NFNL_MSG_ACCT_NOTIFY,
NFNL_MSG_ACCT_MAX
};
@@ -29,6 +29,7 @@ enum {
NFACCT_CMD_ADD,
NFACCT_CMD_DELETE,
NFACCT_CMD_GET,
+ NFACCT_CMD_NOTIFY,
NFACCT_CMD_FLUSH,
NFACCT_CMD_VERSION,
NFACCT_CMD_HELP,
@@ -39,6 +40,7 @@ static int nfacct_cmd_list(int argc, char *argv[]);
static int nfacct_cmd_add(int argc, char *argv[]);
static int nfacct_cmd_delete(int argc, char *argv[]);
static int nfacct_cmd_get(int argc, char *argv[]);
+static int nfacct_cmd_notify(int argc, char *argv[]);
static int nfacct_cmd_flush(int argc, char *argv[]);
static int nfacct_cmd_version(int argc, char *argv[]);
static int nfacct_cmd_help(int argc, char *argv[]);
@@ -76,6 +78,8 @@ int main(int argc, char *argv[])
cmd = NFACCT_CMD_DELETE;
else if (strncmp(argv[1], "get", strlen(argv[1])) == 0)
cmd = NFACCT_CMD_GET;
+ else if (strncmp(argv[1], "notify", strlen(argv[1])) == 0)
+ cmd = NFACCT_CMD_NOTIFY;
else if (strncmp(argv[1], "flush", strlen(argv[1])) == 0)
cmd = NFACCT_CMD_FLUSH;
else if (strncmp(argv[1], "version", strlen(argv[1])) == 0)
@@ -104,6 +108,9 @@ int main(int argc, char *argv[])
case NFACCT_CMD_GET:
ret = nfacct_cmd_get(argc, argv);
break;
+ case NFACCT_CMD_NOTIFY:
+ ret = nfacct_cmd_notify(argc, argv);
+ break;
case NFACCT_CMD_FLUSH:
ret = nfacct_cmd_flush(argc, argv);
break;
@@ -438,6 +445,138 @@ static int nfacct_cmd_get(int argc, char *argv[])
return 0;
}
+static int nfacct_cmd_notify(int argc, char *argv[])
+{
+ bool xml = false;
+ struct mnl_socket *nl;
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
+ uint32_t portid, seq;
+ struct nfacct *nfacct;
+ int ret, i;
+ uint32_t *bytes = NULL, *bytes_rl = NULL;
+ uint32_t *pkts = NULL, *pkts_rl = NULL;
+ uint32_t *period = NULL;
+
+ if (argc < 5) {
+ nfacct_perror("missing object name, bytes, packets or period");
+ return -1;
+ }
+
+ nfacct = nfacct_alloc();
+ if (nfacct == NULL) {
+ nfacct_perror("OOM");
+ return -1;
+ }
+ nfacct_attr_set(nfacct, NFACCT_ATTR_NAME, argv[2]);
+
+ for (i = 3; i < argc; i += 2) {
+ if (strncmp(argv[i], "xml", strlen(argv[i])) == 0) {
+ xml = true;
+ } else if (strncmp(argv[i], "bytes", strlen(argv[i])) == 0) {
+ bytes = malloc(sizeof(uint32_t));
+ if (!bytes)
+ return -ENOMEM;
+ ret = sscanf(argv[i + 1], "%u", bytes);
+ if (ret < 1)
+ goto input_error;
+ nfacct_attr_set(nfacct, NFACCT_ATTR_NOTIFY_BYTES,
+ bytes);
+ } else if (strncmp(argv[i], "bytes-ratelimit",
+ strlen(argv[i])) == 0) {
+ if (!bytes || !*bytes)
+ goto input_error;
+ bytes_rl = malloc(sizeof(uint32_t));
+ if (!bytes_rl)
+ return -ENOMEM;
+ ret = sscanf(argv[i + 1], "%u", bytes_rl);
+ if (ret < 1 || !*bytes_rl)
+ goto input_error;
+ nfacct_attr_set(nfacct, NFACCT_ATTR_NOTIFY_B_RL,
+ bytes_rl);
+ } else if (strncmp(argv[i], "packets", strlen(argv[i])) == 0) {
+ pkts = malloc(sizeof(uint32_t));
+ if (!pkts)
+ return -ENOMEM;
+ ret = sscanf(argv[i + 1], "%u", pkts);
+ if (ret < 1)
+ goto input_error;
+ nfacct_attr_set(nfacct, NFACCT_ATTR_NOTIFY_PKTS, pkts);
+ } else if (strncmp(argv[i], "packets-ratelimit",
+ strlen(argv[i])) == 0) {
+ if (!pkts || !*pkts)
+ goto input_error;
+ pkts_rl = malloc(sizeof(uint32_t));
+ if (!pkts_rl)
+ return -ENOMEM;
+ ret = sscanf(argv[i + 1], "%u", pkts_rl);
+ if (ret < 1 || !*pkts_rl)
+ goto input_error;
+ nfacct_attr_set(nfacct, NFACCT_ATTR_NOTIFY_P_RL,
+ pkts_rl);
+ } else if (strncmp(argv[i], "period", strlen(argv[i])) == 0) {
+ period = malloc(sizeof(uint32_t));
+ if (!period)
+ return -ENOMEM;
+ ret = sscanf(argv[i + 1], "%u", period);
+ if (ret < 1)
+ goto input_error;
+ nfacct_attr_set(nfacct, NFACCT_ATTR_NOTIFY_PERIOD,
+ period);
+ } else {
+ nfacct_perror("unknown argument");
+ return -1;
+ }
+ }
+
+ seq = time(NULL);
+ nlh = nfacct_nlmsg_build_hdr(buf, NFNL_MSG_ACCT_NOTIFY,
+ NLM_F_ACK, seq);
+
+ nfacct_nlmsg_build_payload(nlh, nfacct);
+ nfacct_free(nfacct);
+
+ nl = mnl_socket_open(NETLINK_NETFILTER);
+ if (nl == NULL) {
+ nfacct_perror("mnl_socket_open");
+ return -1;
+ }
+
+ if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
+ nfacct_perror("mnl_socket_bind");
+ return -1;
+ }
+ portid = mnl_socket_get_portid(nl);
+
+ if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
+ nfacct_perror("mnl_socket_send");
+ return -1;
+ }
+
+ ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+ while (ret > 0) {
+ ret = mnl_cb_run(buf, ret, seq, portid, nfacct_cb, &xml);
+ if (ret <= 0 && (errno == EINVAL || errno == ENOENT))
+ break;
+ ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+ }
+ if (ret == -1) {
+ nfacct_perror("error");
+ return -1;
+ }
+
+ mnl_socket_close(nl);
+
+ if (xml_header)
+ printf("</nfacct>\n");
+
+ return 0;
+
+input_error:
+ nfacct_perror("input error");
+ return -1;
+}
+
static int nfacct_cmd_flush(int argc, char *argv[])
{
struct mnl_socket *nl;