1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
|
From d559314e3e3debe1ff8c2c1372701df6154a53ef Mon Sep 17 00:00:00 2001
From: Steven Barth <steven@midlink.org>
Date: Mon, 15 Dec 2014 10:13:39 +0100
Subject: [PATCH 2/3] build: make nftables usable with mini-gmp
libgmp usually compiles to >400KB which can put a burden on embedded
device firmware especially if libgmp isn't used for other purposes.
mini-gmp in contrast adds only ~30KB to the nft-binary itself.
However mini-gmp does not support gmp_sscanf and gmp_printf.
This patch:
* Adds a configure flag --without-libgmp to select mini-gmp
* Replaces the single gmp_sscanf occurence with mpz_set_str
* Replaces calls to gmp_printf outside of pr_debug with
a minimalistic mpz_printf usable to format one mpz_t
* Replaces gmp_vasprintf in erec_vcreate with vasprintf
and rewrites the single user of the gmp format-flags
* Changes the parser token VERSION to IPHDRVERSION to avoid
clashes with the VERSION-define in config.h
Signed-off-by: Steven Barth <cyrus@openwrt.org>
---
configure.ac | 17 ++++++++++++++---
include/expression.h | 2 +-
include/gmputil.h | 10 ++++++++++
include/utils.h | 3 +--
src/Makefile.am | 4 ++++
src/ct.c | 2 +-
src/datatype.c | 8 +++-----
src/erec.c | 6 +++++-
src/evaluate.c | 8 ++++++--
src/gmputil.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++-
src/parser_bison.y | 6 +++---
src/scanner.l | 2 +-
12 files changed, 102 insertions(+), 20 deletions(-)
diff --git a/configure.ac b/configure.ac
index b55b2b1..1e3729d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -73,8 +73,18 @@ AM_CONDITIONAL([BUILD_PDF], [test "$DBLATEX" == "found"])
PKG_CHECK_MODULES([LIBMNL], [libmnl >= 1.0.3])
PKG_CHECK_MODULES([LIBNFTNL], [libnftnl >= 1.0.2])
-AC_CHECK_LIB([gmp], [__gmpz_init], ,
- AC_MSG_ERROR([No suitable version of libgmp found]))
+AC_ARG_WITH([libgmp], [AS_HELP_STRING([--without-libgmp],
+ [Disable libgmp support (use builtin mini-gmp)])], [],
+ [with_libgmp=yes])
+AS_IF([test "x$with_libgmp" != xno], [
+AC_CHECK_LIB([gmp],[__gmpz_init], , AC_MSG_ERROR([No suitable version of libgmp found]))
+])
+AM_CONDITIONAL([BUILD_MINIGMP], [test "x$with_libgmp" == xno])
+
+
+AS_IF([test "x$with_libgmp" != xyes -a "x$CONFIG_DEBUG" = xy], [
+AC_MSG_ERROR([--without-libgmp MUST be used with --disable-debug])
+])
AC_ARG_WITH([cli], [AS_HELP_STRING([--without-cli],
[disable interactive CLI (libreadline support)])],
@@ -130,4 +140,5 @@ AC_OUTPUT
echo "
nft configuration:
cli support: ${with_cli}
- enable debugging: ${with_debug}"
+ enable debugging: ${with_debug}
+ use shared libgmp: ${with_libgmp}"
diff --git a/include/expression.h b/include/expression.h
index 4b96879..7477c3e 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -2,7 +2,7 @@
#define NFTABLES_EXPRESSION_H
#include <stdbool.h>
-#include <gmp.h>
+#include <gmputil.h>
#include <linux/netfilter/nf_tables.h>
#include <nftables.h>
diff --git a/include/gmputil.h b/include/gmputil.h
index 63eb0ba..b9ced6d 100644
--- a/include/gmputil.h
+++ b/include/gmputil.h
@@ -1,9 +1,17 @@
#ifndef NFTABLES_GMPUTIL_H
#define NFTABLES_GMPUTIL_H
+#include <config.h>
+
+#ifdef HAVE_LIBGMP
#include <gmp.h>
+#else
+#include <mini-gmp.h>
+#endif
+
#include <asm/byteorder.h>
+
enum mpz_word_order {
MPZ_MSWF = 1,
MPZ_LSWF = -1,
@@ -48,4 +56,6 @@ extern void mpz_import_data(mpz_t rop, const void *data,
unsigned int len);
extern void mpz_switch_byteorder(mpz_t rop, unsigned int len);
+extern int mpz_printf(const char *format, const mpz_t value);
+
#endif /* NFTABLES_GMPUTIL_H */
diff --git a/include/utils.h b/include/utils.h
index 15b2e39..3c436ba 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -9,14 +9,13 @@
#include <unistd.h>
#include <assert.h>
#include <list.h>
-#include <gmp.h>
#define BITS_PER_BYTE 8
#ifdef DEBUG
#define pr_debug(fmt, arg...) gmp_printf(fmt, ##arg)
#else
-#define pr_debug(fmt, arg...) ({ if (false) gmp_printf(fmt, ##arg); 0; })
+#define pr_debug(fmt, arg...) ({ if (false) {}; 0; })
#endif
#define __fmtstring(x, y) __attribute__((format(printf, x, y)))
diff --git a/src/Makefile.am b/src/Makefile.am
index 378424d..099052a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -51,4 +51,8 @@ if BUILD_CLI
nft_SOURCES += cli.c
endif
+if BUILD_MINIGMP
+nft_SOURCES += mini-gmp.c
+endif
+
nft_LDADD = ${LIBMNL_LIBS} ${LIBNFTNL_LIBS}
diff --git a/src/ct.c b/src/ct.c
index 2eb85ea..759e65d 100644
--- a/src/ct.c
+++ b/src/ct.c
@@ -110,7 +110,7 @@ static void ct_label_type_print(const struct expr *expr)
return;
}
/* can happen when connlabel.conf is altered after rules were added */
- gmp_printf("0x%Zx", expr->value);
+ mpz_printf("0x%Zx", expr->value);
}
static struct error_record *ct_label_type_parse(const struct expr *sym,
diff --git a/src/datatype.c b/src/datatype.c
index 4519d87..40ce898 100644
--- a/src/datatype.c
+++ b/src/datatype.c
@@ -186,7 +186,7 @@ void symbol_table_print(const struct symbol_table *tbl,
static void invalid_type_print(const struct expr *expr)
{
- gmp_printf("0x%Zx [invalid type]", expr->value);
+ mpz_printf("0x%Zx [invalid type]", expr->value);
}
const struct datatype invalid_type = {
@@ -268,18 +268,16 @@ static void integer_type_print(const struct expr *expr)
if (expr->dtype->basefmt != NULL)
fmt = expr->dtype->basefmt;
- gmp_printf(fmt, expr->value);
+ mpz_printf(fmt, expr->value);
}
static struct error_record *integer_type_parse(const struct expr *sym,
struct expr **res)
{
mpz_t v;
- int len;
mpz_init(v);
- if (gmp_sscanf(sym->identifier, "%Zu%n", v, &len) != 1 ||
- (int)strlen(sym->identifier) != len) {
+ if (mpz_set_str(v, sym->identifier, 0)) {
mpz_clear(v);
return error(&sym->location, "Could not parse %s",
sym->dtype->desc);
diff --git a/src/erec.c b/src/erec.c
index 82543e6..810e9bf 100644
--- a/src/erec.c
+++ b/src/erec.c
@@ -44,6 +44,7 @@ static void erec_destroy(struct error_record *erec)
xfree(erec);
}
+__attribute__((format(printf, 3, 0)))
struct error_record *erec_vcreate(enum error_record_types type,
const struct location *loc,
const char *fmt, va_list ap)
@@ -55,10 +56,13 @@ struct error_record *erec_vcreate(enum error_record_types type,
erec->num_locations = 0;
erec_add_location(erec, loc);
- gmp_vasprintf(&erec->msg, fmt, ap);
+ if (vasprintf(&erec->msg, fmt, ap) < 0)
+ erec->msg = NULL;
+
return erec;
}
+__attribute__((format(printf, 3, 4)))
struct error_record *erec_create(enum error_record_types type,
const struct location *loc,
const char *fmt, ...)
diff --git a/src/evaluate.c b/src/evaluate.c
index 0732660..3cb5cca 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -232,9 +232,13 @@ static int expr_evaluate_value(struct eval_ctx *ctx, struct expr **expr)
case TYPE_INTEGER:
mpz_init_bitmask(mask, ctx->ectx.len);
if (mpz_cmp((*expr)->value, mask) > 0) {
+ char *valstr = mpz_get_str(NULL, 10, (*expr)->value);
+ char *rangestr = mpz_get_str(NULL, 10, mask);
expr_error(ctx->msgs, *expr,
- "Value %Zu exceeds valid range 0-%Zu",
- (*expr)->value, mask);
+ "Value %s exceeds valid range 0-%s",
+ valstr, rangestr);
+ free(valstr);
+ free(rangestr);
mpz_clear(mask);
return -1;
}
diff --git a/src/gmputil.c b/src/gmputil.c
index cb46445..acbf369 100644
--- a/src/gmputil.c
+++ b/src/gmputil.c
@@ -14,7 +14,6 @@
#include <stdio.h>
#include <unistd.h>
#include <string.h>
-#include <gmp.h>
#include <nftables.h>
#include <datatype.h>
@@ -148,6 +147,59 @@ void mpz_switch_byteorder(mpz_t rop, unsigned int len)
mpz_import_data(rop, data, BYTEORDER_HOST_ENDIAN, len);
}
+int mpz_printf(const char *f, const mpz_t value)
+{
+ /* minimalistic gmp_printf replacement to format a single mpz_t
+ * using only mini-gmp functions */
+ int n = 0;
+ while (*f) {
+ if (*f != '%') {
+ if (fputc(*f, stdout) != *f)
+ return -1;
+
+ ++n;
+ } else {
+ unsigned long prec = 0;
+ int base;
+ size_t len;
+ char *str;
+ bool ok;
+
+ if (*++f == '.')
+ prec = strtoul(++f, (char**)&f, 10);
+
+ if (*f++ != 'Z')
+ return -1;
+
+ if (*f == 'u')
+ base = 10;
+ else if (*f == 'x')
+ base = 16;
+ else
+ return -1;
+
+ len = mpz_sizeinbase(value, base);
+ while (prec-- > len) {
+ if (fputc('0', stdout) != '0')
+ return -1;
+
+ ++n;
+ }
+
+ str = mpz_get_str(NULL, base, value);
+ ok = str && fwrite(str, 1, len, stdout) == len;
+ free(str);
+
+ if (!ok)
+ return -1;
+
+ n += len;
+ }
+ ++f;
+ }
+ return n;
+}
+
static void *gmp_xrealloc(void *ptr, size_t old_size, size_t new_size)
{
return xrealloc(ptr, new_size);
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 99dbd08..eb5cf90 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -237,7 +237,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%token OPERATION "operation"
%token IP "ip"
-%token VERSION "version"
+%token IPHDRVERSION "version"
%token HDRLENGTH "hdrlength"
%token TOS "tos"
%token LENGTH "length"
@@ -1947,7 +1947,7 @@ ip_hdr_expr : IP ip_hdr_field
}
;
-ip_hdr_field : VERSION { $$ = IPHDR_VERSION; }
+ip_hdr_field : IPHDRVERSION { $$ = IPHDR_VERSION; }
| HDRLENGTH { $$ = IPHDR_HDRLENGTH; }
| TOS { $$ = IPHDR_TOS; }
| LENGTH { $$ = IPHDR_LENGTH; }
@@ -1994,7 +1994,7 @@ ip6_hdr_expr : IP6 ip6_hdr_field
}
;
-ip6_hdr_field : VERSION { $$ = IP6HDR_VERSION; }
+ip6_hdr_field : IPHDRVERSION { $$ = IP6HDR_VERSION; }
| PRIORITY { $$ = IP6HDR_PRIORITY; }
| FLOWLABEL { $$ = IP6HDR_FLOWLABEL; }
| LENGTH { $$ = IP6HDR_LENGTH; }
diff --git a/src/scanner.l b/src/scanner.l
index ed87da6..92b6a10 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -349,7 +349,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"operation" { return OPERATION; }
"ip" { return IP; }
-"version" { return VERSION; }
+"version" { return IPHDRVERSION; }
"hdrlength" { return HDRLENGTH; }
"tos" { return TOS; }
"length" { return LENGTH; }
--
2.1.3
|