libnftnl  1.2.1
byteorder.c
1 /*
2  * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published
6  * by the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
10  */
11 
12 #include "internal.h"
13 
14 #include <stdio.h>
15 #include <stdint.h>
16 #include <string.h> /* for memcpy */
17 #include <arpa/inet.h>
18 #include <errno.h>
19 #include <libmnl/libmnl.h>
20 #include <linux/netfilter/nf_tables.h>
21 #include <libnftnl/expr.h>
22 #include <libnftnl/rule.h>
23 
25  enum nft_registers sreg;
26  enum nft_registers dreg;
27  enum nft_byteorder_ops op;
28  unsigned int len;
29  unsigned int size;
30 };
31 
32 static int
33 nftnl_expr_byteorder_set(struct nftnl_expr *e, uint16_t type,
34  const void *data, uint32_t data_len)
35 {
36  struct nftnl_expr_byteorder *byteorder = nftnl_expr_data(e);
37 
38  switch(type) {
39  case NFTNL_EXPR_BYTEORDER_SREG:
40  memcpy(&byteorder->sreg, data, sizeof(byteorder->sreg));
41  break;
42  case NFTNL_EXPR_BYTEORDER_DREG:
43  memcpy(&byteorder->dreg, data, sizeof(byteorder->dreg));
44  break;
45  case NFTNL_EXPR_BYTEORDER_OP:
46  memcpy(&byteorder->op, data, sizeof(byteorder->op));
47  break;
48  case NFTNL_EXPR_BYTEORDER_LEN:
49  memcpy(&byteorder->len, data, sizeof(byteorder->len));
50  break;
51  case NFTNL_EXPR_BYTEORDER_SIZE:
52  memcpy(&byteorder->size, data, sizeof(byteorder->size));
53  break;
54  default:
55  return -1;
56  }
57  return 0;
58 }
59 
60 static const void *
61 nftnl_expr_byteorder_get(const struct nftnl_expr *e, uint16_t type,
62  uint32_t *data_len)
63 {
64  struct nftnl_expr_byteorder *byteorder = nftnl_expr_data(e);
65 
66  switch(type) {
67  case NFTNL_EXPR_BYTEORDER_SREG:
68  *data_len = sizeof(byteorder->sreg);
69  return &byteorder->sreg;
70  case NFTNL_EXPR_BYTEORDER_DREG:
71  *data_len = sizeof(byteorder->dreg);
72  return &byteorder->dreg;
73  case NFTNL_EXPR_BYTEORDER_OP:
74  *data_len = sizeof(byteorder->op);
75  return &byteorder->op;
76  case NFTNL_EXPR_BYTEORDER_LEN:
77  *data_len = sizeof(byteorder->len);
78  return &byteorder->len;
79  case NFTNL_EXPR_BYTEORDER_SIZE:
80  *data_len = sizeof(byteorder->size);
81  return &byteorder->size;
82  }
83  return NULL;
84 }
85 
86 static int nftnl_expr_byteorder_cb(const struct nlattr *attr, void *data)
87 {
88  const struct nlattr **tb = data;
89  int type = mnl_attr_get_type(attr);
90 
91  if (mnl_attr_type_valid(attr, NFTA_BYTEORDER_MAX) < 0)
92  return MNL_CB_OK;
93 
94  switch(type) {
95  case NFTA_BYTEORDER_SREG:
96  case NFTA_BYTEORDER_DREG:
97  case NFTA_BYTEORDER_OP:
98  case NFTA_BYTEORDER_LEN:
99  case NFTA_BYTEORDER_SIZE:
100  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
101  abi_breakage();
102  break;
103  }
104 
105  tb[type] = attr;
106  return MNL_CB_OK;
107 }
108 
109 static void
110 nftnl_expr_byteorder_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
111 {
112  struct nftnl_expr_byteorder *byteorder = nftnl_expr_data(e);
113 
114  if (e->flags & (1 << NFTNL_EXPR_BYTEORDER_SREG)) {
115  mnl_attr_put_u32(nlh, NFTA_BYTEORDER_SREG,
116  htonl(byteorder->sreg));
117  }
118  if (e->flags & (1 << NFTNL_EXPR_BYTEORDER_DREG)) {
119  mnl_attr_put_u32(nlh, NFTA_BYTEORDER_DREG,
120  htonl(byteorder->dreg));
121  }
122  if (e->flags & (1 << NFTNL_EXPR_BYTEORDER_OP)) {
123  mnl_attr_put_u32(nlh, NFTA_BYTEORDER_OP,
124  htonl(byteorder->op));
125  }
126  if (e->flags & (1 << NFTNL_EXPR_BYTEORDER_LEN)) {
127  mnl_attr_put_u32(nlh, NFTA_BYTEORDER_LEN,
128  htonl(byteorder->len));
129  }
130  if (e->flags & (1 << NFTNL_EXPR_BYTEORDER_SIZE)) {
131  mnl_attr_put_u32(nlh, NFTA_BYTEORDER_SIZE,
132  htonl(byteorder->size));
133  }
134 }
135 
136 static int
137 nftnl_expr_byteorder_parse(struct nftnl_expr *e, struct nlattr *attr)
138 {
139  struct nftnl_expr_byteorder *byteorder = nftnl_expr_data(e);
140  struct nlattr *tb[NFTA_BYTEORDER_MAX+1] = {};
141  int ret = 0;
142 
143  if (mnl_attr_parse_nested(attr, nftnl_expr_byteorder_cb, tb) < 0)
144  return -1;
145 
146  if (tb[NFTA_BYTEORDER_SREG]) {
147  byteorder->sreg =
148  ntohl(mnl_attr_get_u32(tb[NFTA_BYTEORDER_SREG]));
149  e->flags |= (1 << NFTNL_EXPR_BYTEORDER_SREG);
150  }
151  if (tb[NFTA_BYTEORDER_DREG]) {
152  byteorder->dreg =
153  ntohl(mnl_attr_get_u32(tb[NFTA_BYTEORDER_DREG]));
154  e->flags |= (1 << NFTNL_EXPR_BYTEORDER_DREG);
155  }
156  if (tb[NFTA_BYTEORDER_OP]) {
157  byteorder->op =
158  ntohl(mnl_attr_get_u32(tb[NFTA_BYTEORDER_OP]));
159  e->flags |= (1 << NFTNL_EXPR_BYTEORDER_OP);
160  }
161  if (tb[NFTA_BYTEORDER_LEN]) {
162  byteorder->len =
163  ntohl(mnl_attr_get_u32(tb[NFTA_BYTEORDER_LEN]));
164  e->flags |= (1 << NFTNL_EXPR_BYTEORDER_LEN);
165  }
166  if (tb[NFTA_BYTEORDER_SIZE]) {
167  byteorder->size =
168  ntohl(mnl_attr_get_u32(tb[NFTA_BYTEORDER_SIZE]));
169  e->flags |= (1 << NFTNL_EXPR_BYTEORDER_SIZE);
170  }
171 
172  return ret;
173 }
174 
175 static const char *expr_byteorder_str[] = {
176  [NFT_BYTEORDER_HTON] = "hton",
177  [NFT_BYTEORDER_NTOH] = "ntoh",
178 };
179 
180 static const char *bo2str(uint32_t type)
181 {
182  if (type > NFT_BYTEORDER_HTON)
183  return "unknown";
184 
185  return expr_byteorder_str[type];
186 }
187 
188 static inline int nftnl_str2ntoh(const char *op)
189 {
190  if (strcmp(op, "ntoh") == 0)
191  return NFT_BYTEORDER_NTOH;
192  else if (strcmp(op, "hton") == 0)
193  return NFT_BYTEORDER_HTON;
194  else {
195  errno = EINVAL;
196  return -1;
197  }
198 }
199 
200 static int
201 nftnl_expr_byteorder_snprintf(char *buf, size_t remain,
202  uint32_t flags, const struct nftnl_expr *e)
203 {
204  struct nftnl_expr_byteorder *byteorder = nftnl_expr_data(e);
205  int offset = 0, ret;
206 
207  ret = snprintf(buf, remain, "reg %u = %s(reg %u, %u, %u) ",
208  byteorder->dreg, bo2str(byteorder->op),
209  byteorder->sreg, byteorder->size, byteorder->len);
210  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
211 
212  return offset;
213 }
214 
215 struct expr_ops expr_ops_byteorder = {
216  .name = "byteorder",
217  .alloc_len = sizeof(struct nftnl_expr_byteorder),
218  .max_attr = NFTA_BYTEORDER_MAX,
219  .set = nftnl_expr_byteorder_set,
220  .get = nftnl_expr_byteorder_get,
221  .parse = nftnl_expr_byteorder_parse,
222  .build = nftnl_expr_byteorder_build,
223  .snprintf = nftnl_expr_byteorder_snprintf,
224 };