From: Daniel Wagner <daniel.wag...@bmw-carit.de>

---
 src/connman.h   |  32 +++++
 src/netfilter.c | 358 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 390 insertions(+)

diff --git a/src/connman.h b/src/connman.h
index 937d6f2..1ffecf9 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -891,5 +891,37 @@ int __connman_nat_enable(const char *name, const char 
*address,
 void __connman_nat_disable(const char *name);
 
 
+typedef void (*connman_netfilter_acct_new_cb_t) (int error, void *user_data);
+
+typedef void (*connman_netfilter_acct_get_cb_t) (int error, const char *name,
+                                               uint64_t packets,
+                                               uint64_t bytes,
+                                               void *user_data);
+
+typedef void (*connman_netfilter_acct_dump_cb_t) (int error,
+                                               const char *name,
+                                               uint64_t packets,
+                                               uint64_t bytes,
+                                               void *user_data);
+
+typedef void (*connman_netfilter_acct_del_cb_t) (int error,
+                                               void *user_data);
+
+
+unsigned int __connman_netfilter_acct_new(const char *name,
+                                       connman_netfilter_acct_new_cb_t cb,
+                                       void *user_data);
+unsigned int __connman_netfilter_acct_dump(connman_bool_t zero,
+                                       connman_netfilter_acct_dump_cb_t cb,
+                                       void *user_data);
+unsigned int __connman_netfilter_acct_get(const char *name, connman_bool_t 
zero,
+                                       connman_netfilter_acct_get_cb_t cb,
+                                       void *user_data);
+unsigned int __connman_netfilter_acct_del(const char *name,
+                                       connman_netfilter_acct_del_cb_t cb,
+                                       void *user_data);
+
+void __connman_netfilter_cancel(unsigned int id);
+
 int __connman_netfilter_init(void);
 void __connman_netfilter_cleanup(void);
diff --git a/src/netfilter.c b/src/netfilter.c
index 63aa8fc..863e949 100644
--- a/src/netfilter.c
+++ b/src/netfilter.c
@@ -29,15 +29,30 @@
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <linux/genetlink.h>
 #include <linux/netlink.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_acct.h>
 
 #include <gdbus.h>
 
 #include "connman.h"
 
+#define NFMSG_LEN(len) (NLMSG_HDRLEN + NLMSG_ALIGN(GENL_HDRLEN + (len)))
+#define NFGEN_DATA(nlh)        ((void *)((char *)(nlh) +                       
\
+                               NLMSG_ALIGN(sizeof(struct nfgenmsg))))
+#define NLA_DATA(nla)  ((void *)((char*)(nla) + NLA_HDRLEN))
+#define NLA_OK(nla,len) ((len) >= (int)sizeof(struct nlattr) &&                
\
+                               (nla)->nla_len >= sizeof(struct nlattr) && \
+                               (nla)->nla_len <= (len))
+#define NLA_NEXT(nla,attrlen) ((attrlen) -= NLA_ALIGN((nla)->nla_len), \
+                               (struct nlattr*)(((char*)(nla)) +       \
+                                               NLA_ALIGN((nla)->nla_len)))
+
 static GIOChannel *channel;
 
 static GSList *request_list;
+static guint32 request_seq = 1;
 
 typedef void (*connman_netlink_handler_cb_t) (int error,
                                                uint16_t type, const void *data,
@@ -69,6 +84,14 @@ static const char *type2string(uint16_t type)
                return "DONE";
        case NLMSG_OVERRUN:
                return "OVERRUN";
+       case (NFNL_SUBSYS_ACCT << 8) | NFNL_MSG_ACCT_NEW:
+               return "ACCT NEW";
+       case (NFNL_SUBSYS_ACCT << 8) | NFNL_MSG_ACCT_GET:
+               return "ACCT GET";
+       case (NFNL_SUBSYS_ACCT << 8) | NFNL_MSG_ACCT_GET_CTRZERO:
+               return "ACCT GET CTRZERO";
+       case (NFNL_SUBSYS_ACCT << 8) | NFNL_MSG_ACCT_DEL:
+               return "ACCT DEL";
        default:
                return "UNKNOWN";
        }
@@ -93,6 +116,341 @@ static int send_request(struct nlmsghdr *hdr)
                        (struct sockaddr *) &addr, sizeof(addr));
 }
 
+static unsigned int queue_request(struct nlmsghdr *hdr, void *cb,
+                                       void *user_data)
+{
+       struct cb_data *cbd = cb_data_new(cb, user_data);
+       int err;
+
+       cbd->data = hdr;
+
+       DBG("%s len %d type %d flags 0x%04x seq %d",
+                               type2string(hdr->nlmsg_type),
+                               hdr->nlmsg_len, hdr->nlmsg_type,
+                               hdr->nlmsg_flags, hdr->nlmsg_seq);
+
+       request_list = g_slist_append(request_list, cbd);
+       if (g_slist_length(request_list) > 1)
+               goto out;
+
+       err = send_request(hdr);
+       if (err < 0) {
+               request_list = g_slist_remove(request_list, cbd);
+               g_free(hdr);
+               g_free(cbd);
+               return 0;
+       }
+
+out:
+       return hdr->nlmsg_seq;
+}
+
+static void parse_nlattr_acct(const struct nlattr *attr,
+                               char **name, uint64_t *packets, uint64_t *bytes)
+{
+       switch (attr->nla_type) {
+       case NFACCT_NAME:
+               *name = NLA_DATA(attr);
+               break;
+       case NFACCT_PKTS:
+               *packets = be64toh(*(uint64_t *) NLA_DATA(attr));
+               break;
+       case NFACCT_BYTES:
+               *bytes = be64toh(*(uint64_t *) NLA_DATA(attr));
+               break;
+       case NFACCT_USE:
+               /* ignored */
+               break;
+       }
+}
+
+static struct nlmsghdr *create_nf_message(uint16_t type,
+                                       int16_t flags, size_t size)
+{
+       struct nlmsghdr *hdr;
+       struct nfgenmsg *msg;
+
+       hdr = g_try_malloc0(size);
+       if (hdr == NULL)
+               return NULL;
+
+       hdr->nlmsg_len = size;
+       hdr->nlmsg_type = type;
+       hdr->nlmsg_flags = flags;
+       hdr->nlmsg_pid = 0;
+       hdr->nlmsg_seq = request_seq++;
+
+       msg = NLMSG_DATA(hdr);
+       msg->nfgen_family = AF_UNSPEC;
+       msg->version = NFNETLINK_V0;
+       msg->res_id = 0;
+
+       return hdr;
+}
+
+static int append_attr_str(struct nlattr *attr,
+                               uint16_t type, size_t size, const char *str)
+{
+       char *dst;
+
+       attr->nla_len = NLA_HDRLEN + size;
+       attr->nla_type = NFACCT_NAME;
+
+       dst = (char *)NLA_DATA(attr);
+       strncpy(dst, str, size);
+       dst[size - 1] = '\0';
+
+       return 0;
+}
+
+static int nfacct_new_cb(int error, uint16_t type, const void *data,
+                               uint32_t len, void *user_data)
+{
+       struct cb_data *cbd = user_data;
+       connman_netfilter_acct_new_cb_t cb = cbd->cb;
+
+       DBG("type %d len %d", type, len);
+
+       cb(error, cbd->user_data);
+
+       g_free(cbd);
+
+       return 0;
+}
+
+unsigned int __connman_netfilter_acct_new(const char *name,
+                                       connman_netfilter_acct_new_cb_t cb,
+                                       void *user_data)
+{
+       struct cb_data *cbd = cb_data_new(cb, user_data);
+       struct nlmsghdr *nlmsg;
+       struct nlattr *attr;
+       int len, attrlen;
+       unsigned int id;
+
+       DBG("");
+
+       attrlen = strlen(name) + 1;
+       if (attrlen > NFACCT_NAME_MAX)
+               attrlen = NFACCT_NAME_MAX;
+
+       len = NFMSG_LEN(NLA_HDRLEN + attrlen);
+       nlmsg = create_nf_message(
+               (NFNL_SUBSYS_ACCT << 8) | NFNL_MSG_ACCT_NEW,
+               NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK, len);
+       if (nlmsg == NULL) {
+               g_free(cbd);
+               return 0;
+       }
+
+       attr = NFGEN_DATA(NLMSG_DATA(nlmsg));
+       append_attr_str(attr, NFACCT_NAME, attrlen, name);
+
+       id = queue_request(nlmsg, nfacct_new_cb, cbd);
+       if (id == 0) {
+               g_free(nlmsg);
+               g_free(cbd);
+       }
+
+       return id;
+}
+
+static int nfacct_dump_cb(int error, uint16_t type, const void *data,
+                               uint32_t len, void *user_data)
+{
+       struct cb_data *cbd = user_data;
+       const struct nfgenmsg *nfgen = data;
+       connman_netfilter_acct_dump_cb_t cb = cbd->cb;
+       const struct nlattr *attr;
+       uint64_t packets = 0, bytes = 0;
+       char *name = NULL;
+       int attrlen;
+
+       DBG("type %d len %d", type, len);
+
+       if (error < 0)
+               goto done;
+
+       attrlen = len - NLMSG_ALIGN(sizeof(struct nfgenmsg));
+
+       for (attr = NFGEN_DATA(nfgen); NLA_OK(attr, attrlen);
+                       attr = NLA_NEXT(attr, attrlen))
+               parse_nlattr_acct(attr, &name, &packets, &bytes);
+
+done:
+       cb(error, name, packets, bytes, cbd->user_data);
+
+       if (type < NLMSG_MIN_TYPE)
+               g_free(cbd);
+
+       return 0;
+}
+
+unsigned int __connman_netfilter_acct_dump(connman_bool_t zero,
+                                       connman_netfilter_acct_dump_cb_t cb,
+                                       void *user_data)
+{
+       struct cb_data *cbd = cb_data_new(cb, user_data);
+       struct nlmsghdr *nlmsg;
+       unsigned int id;
+       uint16_t cmd;
+       int len;
+
+       DBG("");
+
+       if (zero == FALSE)
+               cmd = NFNL_MSG_ACCT_GET;
+       else
+               cmd = NFNL_MSG_ACCT_GET_CTRZERO;
+
+       len = NFMSG_LEN(0);
+       nlmsg = create_nf_message(
+               (NFNL_SUBSYS_ACCT << 8) | cmd,
+               NLM_F_REQUEST | NLM_F_DUMP, len);
+       if (nlmsg == NULL) {
+               g_free(cbd);
+               return 0;
+       }
+
+       id = queue_request(nlmsg, nfacct_dump_cb, cbd);
+       if (id == 0) {
+               g_free(nlmsg);
+               g_free(cbd);
+       }
+
+       return id;
+}
+
+static int nfacct_get_cb(int error, uint16_t type, const void *data,
+                               uint32_t len, void *user_data)
+{
+       struct cb_data *cbd = user_data;
+       const struct nfgenmsg *nfgen = data;
+       connman_netfilter_acct_get_cb_t cb = cbd->cb;
+       const struct nlattr *attr;
+       uint64_t packets = 0, bytes = 0;
+       char *name = NULL;
+       int attrlen;
+
+       DBG("type %d len %d", type, len);
+
+       if (error < 0) {
+               cb(error, NULL, 0, 0, cbd->user_data);
+               g_free(cbd);
+               return 0;
+       }
+
+       if (type < NLMSG_MIN_TYPE) {
+               g_free(cbd);
+               return 0;
+       }
+
+       attrlen = len - NLMSG_ALIGN(sizeof(struct nfgenmsg));
+
+       for (attr = NFGEN_DATA(nfgen); NLA_OK(attr, attrlen);
+                       attr = NLA_NEXT(attr, attrlen))
+               parse_nlattr_acct(attr, &name, &packets, &bytes);
+
+       cb(error, name, packets, bytes, cbd->user_data);
+
+       return 0;
+}
+
+unsigned int __connman_netfilter_acct_get(const char *name, connman_bool_t 
zero,
+                                       connman_netfilter_acct_get_cb_t cb,
+                                       void *user_data)
+{
+       struct cb_data *cbd = cb_data_new(cb, user_data);
+       struct nlmsghdr *nlmsg;
+       struct nlattr *attr;
+       uint16_t cmd;
+       int len, attrlen;
+       unsigned int id;
+
+       DBG("");
+
+       attrlen = strlen(name) + 1;
+       if (attrlen > NFACCT_NAME_MAX)
+               attrlen = NFACCT_NAME_MAX;
+
+       if (zero == FALSE)
+               cmd = NFNL_MSG_ACCT_GET;
+       else
+               cmd = NFNL_MSG_ACCT_GET_CTRZERO;
+
+       len = NFMSG_LEN(NLA_HDRLEN + attrlen);
+       nlmsg = create_nf_message(
+               (NFNL_SUBSYS_ACCT << 8) | cmd,
+               NLM_F_REQUEST | NLM_F_ACK, len);
+       if (nlmsg == NULL) {
+               g_free(cbd);
+               return 0;
+       }
+
+       attr = NFGEN_DATA(NLMSG_DATA(nlmsg));
+       append_attr_str(attr, NFACCT_NAME, attrlen, name);
+
+       id = queue_request(nlmsg, nfacct_get_cb, cbd);
+       if (id == 0) {
+               g_free(nlmsg);
+               g_free(cbd);
+       }
+
+       return id;
+}
+
+static int nfacct_del_cb(int error, uint16_t type, const void *data,
+                               uint32_t len, void *user_data)
+{
+       struct cb_data *cbd = user_data;
+       connman_netfilter_acct_del_cb_t cb = cbd->cb;
+
+       DBG("type %d len %d", type, len);
+
+       cb(error, cbd->user_data);
+
+       g_free(cbd);
+
+       return 0;
+}
+
+unsigned int __connman_netfilter_acct_del(const char *name,
+                                       connman_netfilter_acct_del_cb_t cb,
+                                       void *user_data)
+{
+       struct cb_data *cbd = cb_data_new(cb, user_data);
+       struct nlmsghdr *nlmsg;
+       struct nlattr *attr;
+       int len, attrlen;
+       unsigned int id;
+
+       DBG("");
+
+       attrlen = strlen(name) + 1;
+       if (attrlen > NFACCT_NAME_MAX)
+               attrlen = NFACCT_NAME_MAX;
+
+       len = NFMSG_LEN(NLA_HDRLEN + attrlen);
+       nlmsg = create_nf_message(
+               (NFNL_SUBSYS_ACCT << 8) | NFNL_MSG_ACCT_DEL,
+               NLM_F_REQUEST | NLM_F_ACK, len);
+       if (nlmsg == NULL) {
+               g_free(cbd);
+               return 0;
+       }
+
+       attr = NFGEN_DATA(NLMSG_DATA(nlmsg));
+       append_attr_str(attr, NFACCT_NAME, attrlen, name);
+
+       id = queue_request(nlmsg, nfacct_del_cb, cbd);
+       if (id == 0) {
+               g_free(nlmsg);
+               g_free(cbd);
+       }
+
+       return id;
+}
+
 static void remove_request(struct cb_data *cbd)
 {
        struct nlmsghdr *hdr = cbd->data;
-- 
1.8.1.3.566.gaa39828

_______________________________________________
connman mailing list
connman@connman.net
http://lists.connman.net/listinfo/connman

Reply via email to