OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / freeswan / lib / rangetosubnet.c
1 /*
2  * express an address range as a subnet (if possible)
3  * Copyright (C) 2000  Henry Spencer.
4  * 
5  * This library is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU Library General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or (at your
8  * option) any later version.  See <http://www.fsf.org/copyleft/lgpl.txt>.
9  * 
10  * This library is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
13  * License for more details.
14  *
15  * RCSID $Id: rangetosubnet.c,v 1.5 2000/09/08 18:03:45 henry Exp $
16  */
17 #include "internal.h"
18 #include "freeswan.h"
19
20 /*
21  - rangetosubnet - turn an address range into a subnet, if possible
22  *
23  * A range which is a valid subnet will have a network part which is the
24  * same in the from value and the to value, followed by a host part which
25  * is all 0 in the from value and all 1 in the to value.
26  */
27 err_t
28 rangetosubnet(from, to, dst)
29 const ip_address *from;
30 const ip_address *to;
31 ip_subnet *dst;
32 {
33         unsigned const char *fp;
34         unsigned const char *tp;
35         unsigned fb;
36         unsigned tb;
37         unsigned const char *f;
38         unsigned const char *t;
39         size_t n;
40         size_t n2;
41         int i;
42         int nnet;
43         unsigned m;
44
45         if (addrtypeof(from) != addrtypeof(to))
46                 return "mismatched address types";
47         n = addrbytesptr(from, &fp);
48         if (n == 0)
49                 return "unknown address type";
50         n2 = addrbytesptr(to, &tp);
51         if (n != n2)
52                 return "internal size mismatch in rangetosubnet";
53
54         f = fp;
55         t = tp;
56         nnet = 0;
57         for (i = n; i > 0 && *f == *t; i--, f++, t++)
58                 nnet += 8;
59         if (i > 0 && !(*f == 0x00 && *t == 0xff)) {     /* mid-byte bdry. */
60                 fb = *f++;
61                 tb = *t++;
62                 i--;
63                 m = 0x80;
64                 while ((fb&m) == (tb&m)) {
65                         fb &= ~m;
66                         tb |= m;
67                         m >>= 1;
68                         nnet++;
69                 }
70                 if (fb != 0x00 || tb != 0xff)
71                         return "not a valid subnet";
72         }
73         for (; i > 0 && *f == 0x00 && *t == 0xff; i--, f++, t++)
74                 continue;
75
76         if (i != 0)
77                 return "invalid subnet";
78
79         return initsubnet(from, nnet, 'x', dst);
80 }
81
82
83
84 #ifdef RANGETOSUBNET_MAIN
85
86 #include <stdio.h>
87
88 void regress();
89
90 int
91 main(argc, argv)
92 int argc;
93 char *argv[];
94 {
95         ip_address start;
96         ip_address stop;
97         ip_subnet sub;
98         char buf[100];
99         const char *oops;
100         size_t n;
101         int af;
102         int i;
103
104         if (argc == 2 && strcmp(argv[1], "-r") == 0) {
105                 regress();
106                 fprintf(stderr, "regress() returned?!?\n");
107                 exit(1);
108         }
109
110         if (argc < 3) {
111                 fprintf(stderr, "Usage: %s [-6] start stop\n", argv[0]);
112                 fprintf(stderr, "   or: %s -r\n", argv[0]);
113                 exit(2);
114         }
115
116         af = AF_INET;
117         i = 1;
118         if (strcmp(argv[i], "-6") == 0) {
119                 af = AF_INET6;
120                 i++;
121         }
122
123         oops = ttoaddr(argv[i], 0, af, &start);
124         if (oops != NULL) {
125                 fprintf(stderr, "%s: start conversion failed: %s\n", argv[0], oops);
126                 exit(1);
127         }
128         oops = ttoaddr(argv[i+1], 0, af, &stop);
129         if (oops != NULL) {
130                 fprintf(stderr, "%s: stop conversion failed: %s\n", argv[0], oops);
131                 exit(1);
132         }
133         oops = rangetosubnet(&start, &stop, &sub);
134         if (oops != NULL) {
135                 fprintf(stderr, "%s: rangetosubnet failed: %s\n", argv[0], oops);
136                 exit(1);
137         }
138         n = subnettot(&sub, 0, buf, sizeof(buf));
139         if (n > sizeof(buf)) {
140                 fprintf(stderr, "%s: reverse conversion", argv[0]);
141                 fprintf(stderr, " failed: need %ld bytes, have only %ld\n",
142                                                 (long)n, (long)sizeof(buf));
143                 exit(1);
144         }
145         printf("%s\n", buf);
146
147         exit(0);
148 }
149
150 struct rtab {
151         int family;
152         char *start;
153         char *stop;
154         char *output;                   /* NULL means error expected */
155 } rtab[] = {
156         4, "1.2.3.0",           "1.2.3.255",            "1.2.3.0/24",
157         4, "1.2.3.0",           "1.2.3.7",              "1.2.3.0/29",
158         4, "1.2.3.240",         "1.2.3.255",            "1.2.3.240/28",
159         4, "0.0.0.0",           "255.255.255.255",      "0.0.0.0/0",
160         4, "1.2.3.4",           "1.2.3.4",              "1.2.3.4/32",
161         4, "1.2.3.0",           "1.2.3.254",            NULL,
162         4, "1.2.3.0",           "1.2.3.126",            NULL,
163         4, "1.2.3.0",           "1.2.3.125",            NULL,
164         4, "1.2.0.0",           "1.2.255.255",          "1.2.0.0/16",
165         4, "1.2.0.0",           "1.2.0.255",            "1.2.0.0/24",
166         4, "1.2.255.0",         "1.2.255.255",          "1.2.255.0/24",
167         4, "1.2.255.0",         "1.2.254.255",          NULL,
168         4, "1.2.255.1",         "1.2.255.255",          NULL,
169         4, "1.2.0.1",           "1.2.255.255",          NULL,
170         6, "1:2:3:4:5:6:7:0",   "1:2:3:4:5:6:7:ffff",   "1:2:3:4:5:6:7:0/112",
171         6, "1:2:3:4:5:6:7:0",   "1:2:3:4:5:6:7:fff",    "1:2:3:4:5:6:7:0/116",
172         6, "1:2:3:4:5:6:7:f0",  "1:2:3:4:5:6:7:ff",     "1:2:3:4:5:6:7:f0/124",
173         4, NULL,                NULL,                   NULL,
174 };
175
176 void
177 regress()
178 {
179         struct rtab *r;
180         int status = 0;
181         ip_address start;
182         ip_address stop;
183         ip_subnet sub;
184         char buf[100];
185         const char *oops;
186         size_t n;
187         int af;
188
189         for (r = rtab; r->start != NULL; r++) {
190                 af = (r->family == 4) ? AF_INET : AF_INET6;
191                 oops = ttoaddr(r->start, 0, af, &start);
192                 if (oops != NULL) {
193                         printf("surprise failure converting `%s'\n", r->start);
194                         exit(1);
195                 }
196                 oops = ttoaddr(r->stop, 0, af, &stop);
197                 if (oops != NULL) {
198                         printf("surprise failure converting `%s'\n", r->stop);
199                         exit(1);
200                 }
201                 oops = rangetosubnet(&start, &stop, &sub);
202                 if (oops != NULL && r->output == NULL)
203                         {}              /* okay, error expected */
204                 else if (oops != NULL) {
205                         printf("`%s'-`%s' rangetosubnet failed: %s\n",
206                                                 r->start, r->stop, oops);
207                         status = 1;
208                 } else if (r->output == NULL) {
209                         printf("`%s'-`%s' rangetosubnet succeeded unexpectedly\n",
210                                                         r->start, r->stop);
211                         status = 1;
212                 } else {
213                         n = subnettot(&sub, 0, buf, sizeof(buf));
214                         if (n > sizeof(buf)) {
215                                 printf("`%s'-`%s' subnettot failed:  need %ld\n",
216                                                 r->start, r->stop, (long)n);
217                                 status = 1;
218                         } else if (strcmp(r->output, buf) != 0) {
219                                 printf("`%s'-`%s' gave `%s', expected `%s'\n",
220                                         r->start, r->stop, buf, r->output);
221                                 status = 1;
222                         }
223                 }
224         }
225         exit(status);
226 }
227
228 #endif /* RANGETOSUBNET_MAIN */