~ubuntu-branches/debian/stretch/haproxy/stretch

« back to all changes in this revision

Viewing changes to contrib/ip6range/ip6range.c

  • Committer: Package Import Robot
  • Author(s): Apollon Oikonomopoulos
  • Date: 2014-06-20 11:05:17 UTC
  • mfrom: (1.1.15) (15.1.12 experimental)
  • Revision ID: package-import@ubuntu.com-20140620110517-u6q5p9kyy2f3ozw9
Tags: 1.5.0-1
* New upstream stable series. Notable changes since the 1.4 series:
  + Native SSL support on both sides with SNI/NPN/ALPN and OCSP stapling.
  + IPv6 and UNIX sockets are supported everywhere
  + End-to-end HTTP keep-alive for better support of NTLM and improved
    efficiency in static farms
  + HTTP/1.1 response compression (deflate, gzip) to save bandwidth
  + PROXY protocol versions 1 and 2 on both sides
  + Data sampling on everything in request or response, including payload
  + ACLs can use any matching method with any input sample
  + Maps and dynamic ACLs updatable from the CLI
  + Stick-tables support counters to track activity on any input sample
  + Custom format for logs, unique-id, header rewriting, and redirects
  + Improved health checks (SSL, scripted TCP, check agent, ...)
  + Much more scalable configuration supports hundreds of thousands of
    backends and certificates without sweating

* Upload to unstable, merge all 1.5 work from experimental. Most important
  packaging changes since 1.4.25-1 include:
  + systemd support.
  + A more sane default config file.
  + Zero-downtime upgrades between 1.5 releases by gracefully reloading
    HAProxy during upgrades.
  + HTML documentation shipped in the haproxy-doc package.
  + kqueue support for kfreebsd.

* Packaging changes since 1.5~dev26-2:
  + Drop patches merged upstream:
    o Fix-reference-location-in-manpage.patch
    o 0001-BUILD-stats-workaround-stupid-and-bogus-Werror-forma.patch
  + d/watch: look for stable 1.5 releases
  + systemd: respect CONFIG and EXTRAOPTS when specified in
    /etc/default/haproxy.
  + initscript: test the configuration before start or reload.
  + initscript: remove the ENABLED flag and logic.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * network range to IP+mask converter
 
3
 *
 
4
 * Copyright 2011-2012 Willy Tarreau <w@1wt.eu>
 
5
 *
 
6
 * This program reads lines starting by two IP addresses and outputs them with
 
7
 * the two IP addresses replaced by a netmask covering the range between these
 
8
 * IPs (inclusive). When multiple ranges are needed, as many lines are emitted.
 
9
 * The IP addresses may be delimited by spaces, tabs or commas. Quotes are
 
10
 * stripped, and lines beginning with a sharp character ('#') are ignored. The
 
11
 * IP addresses may be either in the dotted format or represented as a 32-bit
 
12
 * integer value in network byte order.
 
13
 *
 
14
 * This program is free software; you can redistribute it and/or
 
15
 * modify it under the terms of the GNU General Public License
 
16
 * as published by the Free Software Foundation; either version
 
17
 * 2 of the License, or (at your option) any later version.
 
18
 */
 
19
 
 
20
#include <sys/types.h>
 
21
#include <sys/socket.h>
 
22
#include <arpa/inet.h>
 
23
#include <stdio.h>
 
24
#include <stdlib.h>
 
25
#include <string.h>
 
26
 
 
27
#define MAXLINE 1024
 
28
 
 
29
static inline void in6_bswap(struct in6_addr *a)
 
30
{
 
31
        a->in6_u.u6_addr32[0] = ntohl(a->in6_u.u6_addr32[0]);
 
32
        a->in6_u.u6_addr32[1] = ntohl(a->in6_u.u6_addr32[1]);
 
33
        a->in6_u.u6_addr32[2] = ntohl(a->in6_u.u6_addr32[2]);
 
34
        a->in6_u.u6_addr32[3] = ntohl(a->in6_u.u6_addr32[3]);
 
35
}
 
36
 
 
37
/* returns a string version of an IPv6 address in host order */
 
38
static const char *get_ipv6_addr(struct in6_addr *addr)
 
39
{
 
40
        struct in6_addr a;
 
41
        static char out[INET6_ADDRSTRLEN + 1];
 
42
 
 
43
        memcpy(&a, addr, sizeof(struct in6_addr));
 
44
        in6_bswap(&a);
 
45
        return inet_ntop(AF_INET6, &a, out, INET6_ADDRSTRLEN + 1);
 
46
}
 
47
 
 
48
static const char *get_addr(struct in6_addr *addr)
 
49
{
 
50
        static char out[50];
 
51
        snprintf(out, 50, "%08x:%08x:%08x:%08x",
 
52
                 addr->in6_u.u6_addr32[0],
 
53
                 addr->in6_u.u6_addr32[1],
 
54
                 addr->in6_u.u6_addr32[2],
 
55
                 addr->in6_u.u6_addr32[3]);
 
56
        return out;
 
57
}
 
58
 
 
59
/* a <= b */
 
60
static inline int a_le_b(struct in6_addr *a, struct in6_addr *b)
 
61
{
 
62
        if (a->in6_u.u6_addr32[0] < b->in6_u.u6_addr32[0]) return 1;
 
63
        if (a->in6_u.u6_addr32[0] > b->in6_u.u6_addr32[0]) return 0;
 
64
        if (a->in6_u.u6_addr32[1] < b->in6_u.u6_addr32[1]) return 1;
 
65
        if (a->in6_u.u6_addr32[1] > b->in6_u.u6_addr32[1]) return 0;
 
66
        if (a->in6_u.u6_addr32[2] < b->in6_u.u6_addr32[2]) return 1;
 
67
        if (a->in6_u.u6_addr32[2] > b->in6_u.u6_addr32[2]) return 0;
 
68
        if (a->in6_u.u6_addr32[3] < b->in6_u.u6_addr32[3]) return 1;
 
69
        if (a->in6_u.u6_addr32[3] > b->in6_u.u6_addr32[3]) return 0;
 
70
        return 1;
 
71
}
 
72
 
 
73
/* a == b */
 
74
static inline int a_eq_b(struct in6_addr *a, struct in6_addr *b)
 
75
{
 
76
        if (a->in6_u.u6_addr32[0] != b->in6_u.u6_addr32[0]) return 0;
 
77
        if (a->in6_u.u6_addr32[1] != b->in6_u.u6_addr32[1]) return 0;
 
78
        if (a->in6_u.u6_addr32[2] != b->in6_u.u6_addr32[2]) return 0;
 
79
        if (a->in6_u.u6_addr32[3] != b->in6_u.u6_addr32[3]) return 0;
 
80
        return 1;
 
81
}
 
82
 
 
83
/* a > b */
 
84
static inline int a_gt_b(struct in6_addr *a, struct in6_addr *b)
 
85
{
 
86
        if (a->in6_u.u6_addr32[0] > b->in6_u.u6_addr32[0]) return 1;
 
87
        if (a->in6_u.u6_addr32[0] < b->in6_u.u6_addr32[0]) return 0;
 
88
        if (a->in6_u.u6_addr32[1] > b->in6_u.u6_addr32[1]) return 1;
 
89
        if (a->in6_u.u6_addr32[1] < b->in6_u.u6_addr32[1]) return 0;
 
90
        if (a->in6_u.u6_addr32[2] > b->in6_u.u6_addr32[2]) return 1;
 
91
        if (a->in6_u.u6_addr32[2] < b->in6_u.u6_addr32[2]) return 0;
 
92
        if (a->in6_u.u6_addr32[3] > b->in6_u.u6_addr32[3]) return 1;
 
93
        if (a->in6_u.u6_addr32[3] < b->in6_u.u6_addr32[3]) return 0;
 
94
        return 0;
 
95
}
 
96
 
 
97
/* ( 1 << m ) - 1 -> r */
 
98
static inline struct in6_addr *hmask(unsigned int b, struct in6_addr *r)
 
99
{
 
100
 
 
101
        if (b < 32) {
 
102
                r->in6_u.u6_addr32[3] = (1 << b) - 1;
 
103
                r->in6_u.u6_addr32[2] = 0;
 
104
                r->in6_u.u6_addr32[1] = 0;
 
105
                r->in6_u.u6_addr32[0] = 0;
 
106
        }
 
107
        else if (b < 64) {
 
108
                r->in6_u.u6_addr32[3] = 0xffffffff;
 
109
                r->in6_u.u6_addr32[2] = (1 << (b - 32)) - 1;
 
110
                r->in6_u.u6_addr32[1] = 0;
 
111
                r->in6_u.u6_addr32[0] = 0;
 
112
        }
 
113
        else if (b < 96) {
 
114
                r->in6_u.u6_addr32[3] = 0xffffffff;
 
115
                r->in6_u.u6_addr32[2] = 0xffffffff;
 
116
                r->in6_u.u6_addr32[1] = (1 << (b - 64)) - 1;
 
117
                r->in6_u.u6_addr32[0] = 0;
 
118
        }
 
119
        else if (b < 128) {
 
120
                r->in6_u.u6_addr32[3] = 0xffffffff;
 
121
                r->in6_u.u6_addr32[2] = 0xffffffff;
 
122
                r->in6_u.u6_addr32[1] = 0xffffffff;
 
123
                r->in6_u.u6_addr32[0] = (1 << (b - 96)) - 1;
 
124
        }
 
125
        else {
 
126
                r->in6_u.u6_addr32[3] = 0xffffffff;
 
127
                r->in6_u.u6_addr32[2] = 0xffffffff;
 
128
                r->in6_u.u6_addr32[1] = 0xffffffff;
 
129
                r->in6_u.u6_addr32[0] = 0xffffffff;
 
130
        }
 
131
        return r;
 
132
}
 
133
 
 
134
/* 1 << b -> r */
 
135
static inline struct in6_addr *one_ls_b(unsigned int b, struct in6_addr *r)
 
136
{
 
137
        if (b < 32) {
 
138
                r->in6_u.u6_addr32[3] = 1 << b;
 
139
                r->in6_u.u6_addr32[2] = 0;
 
140
                r->in6_u.u6_addr32[1] = 0;
 
141
                r->in6_u.u6_addr32[0] = 0;
 
142
        }
 
143
        else if (b < 64) {
 
144
                r->in6_u.u6_addr32[3] = 0;
 
145
                r->in6_u.u6_addr32[2] = 1 << (b - 32);
 
146
                r->in6_u.u6_addr32[1] = 0;
 
147
                r->in6_u.u6_addr32[0] = 0;
 
148
        }
 
149
        else if (b < 96) {
 
150
                r->in6_u.u6_addr32[3] = 0;
 
151
                r->in6_u.u6_addr32[2] = 0;
 
152
                r->in6_u.u6_addr32[1] = 1 << (b - 64);
 
153
                r->in6_u.u6_addr32[0] = 0;
 
154
        }
 
155
        else if (b < 128) {
 
156
                r->in6_u.u6_addr32[3] = 0;
 
157
                r->in6_u.u6_addr32[2] = 0;
 
158
                r->in6_u.u6_addr32[1] = 0;
 
159
                r->in6_u.u6_addr32[0] = 1 << (b - 96);
 
160
        }
 
161
        else {
 
162
                r->in6_u.u6_addr32[3] = 0;
 
163
                r->in6_u.u6_addr32[2] = 0;
 
164
                r->in6_u.u6_addr32[1] = 0;
 
165
                r->in6_u.u6_addr32[0] = 0;
 
166
        }
 
167
        return r;
 
168
}
 
169
 
 
170
/* a + b -> r */
 
171
static inline struct in6_addr *a_plus_b(struct in6_addr *a, struct in6_addr *b, struct in6_addr *r)
 
172
{
 
173
        unsigned long long int c = 0;
 
174
        int i;
 
175
 
 
176
        for (i=3; i>=0; i--) {
 
177
                c = (unsigned long long int)a->in6_u.u6_addr32[i] +
 
178
                    (unsigned long long int)b->in6_u.u6_addr32[i] + c;
 
179
                r->in6_u.u6_addr32[i] = c;
 
180
                c >>= 32;
 
181
        }
 
182
 
 
183
        return r;
 
184
}
 
185
 
 
186
/* a - b -> r */
 
187
static inline struct in6_addr *a_minus_b(struct in6_addr *a, struct in6_addr *b, struct in6_addr *r)
 
188
{
 
189
        signed long long int c = 0;
 
190
        signed long long int d;
 
191
        int i;
 
192
 
 
193
        /* Check sign. Return 0xff..ff (-1) if the result is less than 0. */
 
194
        if (a_gt_b(b, a)) {
 
195
                r->in6_u.u6_addr32[3] = 0xffffffff;
 
196
                r->in6_u.u6_addr32[2] = 0xffffffff;
 
197
                r->in6_u.u6_addr32[1] = 0xffffffff;
 
198
                r->in6_u.u6_addr32[0] = 0xffffffff;
 
199
                return r;
 
200
        }
 
201
 
 
202
        for (i=3; i>=0; i--) {
 
203
                d = (unsigned long long int)b->in6_u.u6_addr32[i] + c;
 
204
                c = (unsigned long long int)a->in6_u.u6_addr32[i];
 
205
                if (c < d)
 
206
                        c += 0x100000000ULL;
 
207
                c -= d;
 
208
                r->in6_u.u6_addr32[i] = c;
 
209
                c >>= 32;
 
210
        }
 
211
 
 
212
        return r;
 
213
}
 
214
 
 
215
/* a & b -> r */
 
216
static inline struct in6_addr *a_and_b(struct in6_addr *a, struct in6_addr *b, struct in6_addr *r)
 
217
{
 
218
        r->in6_u.u6_addr32[0] = a->in6_u.u6_addr32[0] & b->in6_u.u6_addr32[0];
 
219
        r->in6_u.u6_addr32[1] = a->in6_u.u6_addr32[1] & b->in6_u.u6_addr32[1];
 
220
        r->in6_u.u6_addr32[2] = a->in6_u.u6_addr32[2] & b->in6_u.u6_addr32[2];
 
221
        r->in6_u.u6_addr32[3] = a->in6_u.u6_addr32[3] & b->in6_u.u6_addr32[3];
 
222
        return r;
 
223
}
 
224
 
 
225
/* a != 0 */
 
226
int is_set(struct in6_addr *a)
 
227
{
 
228
        return a->in6_u.u6_addr32[0] ||
 
229
               a->in6_u.u6_addr32[1] ||
 
230
               a->in6_u.u6_addr32[2] ||
 
231
               a->in6_u.u6_addr32[3];
 
232
}
 
233
 
 
234
/* 1 */
 
235
static struct in6_addr one = { .in6_u.u6_addr32 = {0, 0, 0, 1} };
 
236
 
 
237
/* print all networks present between address <low> and address <high> in
 
238
 * cidr format, followed by <eol>.
 
239
 */
 
240
static void convert_range(struct in6_addr *low, struct in6_addr *high, const char *eol, const char *pfx)
 
241
{
 
242
        int bit;
 
243
        struct in6_addr r0;
 
244
        struct in6_addr r1;
 
245
 
 
246
        if (a_eq_b(low, high)) {
 
247
                /* single value */
 
248
                printf("%s%s%s%s\n", pfx?pfx:"", pfx?" ":"", get_ipv6_addr(low), eol);
 
249
                return;
 
250
        }
 
251
        else if (a_gt_b(low, high)) {
 
252
                struct in6_addr *swap = low;
 
253
                low = high;
 
254
                high = swap;
 
255
        }
 
256
 
 
257
        if (a_eq_b(low, a_plus_b(high, &one, &r0))) {
 
258
                /* full range */
 
259
                printf("%s%s::/0%s\n", pfx?pfx:"", pfx?" ":"", eol);
 
260
                return;
 
261
        }
 
262
        //printf("low=%08x high=%08x\n", low, high);
 
263
 
 
264
        bit = 0;
 
265
        while (bit < 128 && a_le_b(a_plus_b(low, hmask(bit, &r0), &r0), high)) {
 
266
 
 
267
                /* enlarge mask */
 
268
                if (is_set(a_and_b(low, one_ls_b(bit, &r0), &r0))) {
 
269
                        /* can't aggregate anymore, dump and retry from the same bit */
 
270
                        printf("%s%s%s/%d%s\n", pfx?pfx:"", pfx?" ":"", get_ipv6_addr(low), 128-bit, eol);
 
271
                        a_plus_b(low, one_ls_b(bit, &r0), low);
 
272
                }
 
273
                else {
 
274
                        /* try to enlarge the mask as much as possible first */
 
275
                        bit++;
 
276
                        //printf("  ++bit=%d\n", bit);
 
277
                }
 
278
        }
 
279
        //printf("stopped 1 at low=%08x, bit=%d\n", low, bit);
 
280
 
 
281
        bit = 127;
 
282
        while (bit >= 0 && is_set(a_plus_b(a_minus_b(high, low, &r0), &one, &r0))) {
 
283
 
 
284
                /* shrink mask */
 
285
                if (is_set(a_and_b(a_plus_b(a_minus_b(high, low, &r0), &one, &r0), one_ls_b(bit, &r1), &r1))) {
 
286
                        /* large bit accepted, dump and go on from the same bit */
 
287
                        //printf("max: %08x/%d\n", low, 32-bit);
 
288
                        printf("%s%s%s/%d%s\n", pfx?pfx:"", pfx?" ":"", get_ipv6_addr(low), 128-bit, eol);
 
289
                        a_plus_b(low, one_ls_b(bit, &r0), low);
 
290
                }
 
291
                else {
 
292
                        bit--;
 
293
                        //printf("  --bit=%d, low=%08x\n", bit, low);
 
294
                }
 
295
        }
 
296
        //printf("stopped at low=%08x\n", low);
 
297
}
 
298
 
 
299
static void usage(const char *argv0)
 
300
{
 
301
        fprintf(stderr,
 
302
                "Usage: %s [<addr> ...] < iplist.csv\n"
 
303
                "\n"
 
304
                "This program reads lines starting by two IP addresses and outputs them with\n"
 
305
                "the two IP addresses replaced by a netmask covering the range between these\n"
 
306
                "IPs (inclusive). When multiple ranges are needed, as many lines are emitted.\n"
 
307
                "The IP addresses may be delimited by spaces, tabs or commas. Quotes are\n"
 
308
                "stripped, and lines beginning with a sharp character ('#') are ignored. The\n"
 
309
                "IP addresses may be either in the dotted format or represented as a 32-bit\n"
 
310
                "integer value in network byte order.\n"
 
311
                "\n"
 
312
                "For each optional <addr> specified, only the network it belongs to is returned,\n"
 
313
                "prefixed with the <addr> value.\n"
 
314
                "\n", argv0);
 
315
}
 
316
 
 
317
main(int argc, char **argv)
 
318
{
 
319
        char line[MAXLINE];
 
320
        int l, lnum;
 
321
        char *lb, *le, *hb, *he, *err;
 
322
        struct in6_addr sa, da, ta;
 
323
 
 
324
        if (argc > 1 && *argv[1] == '-') {
 
325
                usage(argv[0]);
 
326
                exit(1);
 
327
        }
 
328
 
 
329
        lnum = 0;
 
330
        while (fgets(line, sizeof(line), stdin) != NULL) {
 
331
                l = strlen(line);
 
332
                if (l && line[l - 1] == '\n')
 
333
                        line[--l] = '\0';
 
334
 
 
335
                lnum++;
 
336
                /* look for the first field which must be the low address of a range,
 
337
                 * in dotted IPv4 format or as an integer. spaces and commas are
 
338
                 * considered as delimiters, quotes are removed.
 
339
                 */
 
340
                for (lb = line; *lb == ' ' || *lb == '\t' || *lb == ',' || *lb == '"'; lb++);
 
341
                if (!*lb || *lb == '#')
 
342
                        continue;
 
343
                for (le = lb + 1; *le != ' ' && *le != '\t' && *le != ',' && *le != '"' && *le; le++);
 
344
                if (!*le)
 
345
                        continue;
 
346
                /* we have the low address between lb(included) and le(excluded) */
 
347
                *(le++) = 0;
 
348
 
 
349
                for (hb = le; *hb == ' ' || *hb == '\t' || *hb == ',' || *hb == '"'; hb++);
 
350
                if (!*hb || *hb == '#')
 
351
                        continue;
 
352
                for (he = hb + 1; *he != ' ' && *he != '\t' && *he != ',' && *he != '"' && *he; he++);
 
353
                if (!*he)
 
354
                        continue;
 
355
                /* we have the high address between hb(included) and he(excluded) */
 
356
                *(he++) = 0;
 
357
 
 
358
                /* we want to remove a possible ending quote and a possible comma,
 
359
                 * not more.
 
360
                 */
 
361
                while (*he == '"')
 
362
                        *(he++) = ' ';
 
363
                while (*he == ',' || *he == ' ' || *he == '\t')
 
364
                        *(he++) = ' ';
 
365
 
 
366
                /* if the trailing string is not empty, prefix it with a space */
 
367
                if (*(he-1) == ' ')
 
368
                        he--;
 
369
 
 
370
                if (inet_pton(AF_INET6, lb, &sa) <= 0) {
 
371
                        fprintf(stderr, "Failed to parse source address <%s> at line %d, skipping line\n", lb, lnum);
 
372
                        continue;
 
373
                }
 
374
 
 
375
                if (inet_pton(AF_INET6, hb, &da) <= 0) {
 
376
                        fprintf(stderr, "Failed to parse destination address <%s> at line %d, skipping line\n", hb, lnum);
 
377
                        continue;
 
378
                }
 
379
 
 
380
                in6_bswap(&sa);
 
381
                in6_bswap(&da);
 
382
 
 
383
                if (argc > 1) {
 
384
                        for (l = 1; l < argc; l++) {
 
385
                                if (inet_pton(AF_INET6, argv[l], &da) <= 0)
 
386
                                        continue;
 
387
                                in6_bswap(&ta);
 
388
                                if ((a_le_b(&sa, &ta) && a_le_b(&ta, &da)) || (a_le_b(&da, &ta) && a_le_b(&ta, &sa)))
 
389
                                        convert_range(&sa, &da, he, argv[l]);
 
390
                        }
 
391
                }
 
392
                else {
 
393
                        convert_range(&sa, &da, he, NULL);
 
394
                }
 
395
        }
 
396
}