Bug Summary

File:netmask.c
Location:line 362, column 7
Description:Access to field 'neta' results in a dereference of a null pointer (loaded from variable 'lst')

Annotated Source Code

1/* netmask.c - a netmask generator
2 *
3 * Copyright (c) 1999 Robert Stone <talby@trap.mtview.ca.us>,
4 * Tom Lear <tom@trap.mtview.ca.us>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#include <arpa/inet.h>
21#include <getopt.h>
22#include <netdb.h>
23#include <netinet/in.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <sys/socket.h>
28#include <sys/types.h>
29#include "errors.h"
30
31struct addrmask {
32 u_int32_t neta;
33 u_int32_t mask;
34 struct addrmask *next;
35 struct addrmask *prev;
36};
37
38struct option longopts[] = {
39 { "version", 0, 0, 'v' },
40 { "help", 0, 0, 'h' },
41 { "debug", 0, 0, 'd' },
42 { "standard", 0, 0, 's' },
43 { "cidr", 0, 0, 'c' },
44 { "cisco", 0, 0, 'i' },
45 { "range", 0, 0, 'r' },
46 { "hex", 0, 0, 'x' },
47 { "octal", 0, 0, 'o' },
48 { "binary", 0, 0, 'b' },
49 { "nodns", 0, 0, 'n' },
50 { "max", 1, 0, 'M' },
51 { "min", 1, 0, 'm' },
52 { NULL((void*)0), 0, 0, 0 }
53};
54
55typedef enum {
56 OUT_STD, OUT_CIDR, OUT_CISCO, OUT_RANGE, OUT_HEX, OUT_OCTAL, OUT_BINARY
57} output_t;
58
59int spectoaml(char *, int);
60int display(output_t);
61int addtoaml(u_int32_t addr, u_int32_t mask);
62static u_int32_t mspectou32(char *);
63
64char version[] = "netmask, version "VERSION"2.3.7";
65char vversion[] = __DATE__"Feb 2 2014"" "__TIME__"20:03:45";
66char usage[] = "Try `%s --help' for more information.\n";
67char *progname = NULL((void*)0);
68static struct addrmask *aml;
69
70int main(int argc, char *argv[]) {
71 int optc, h = 0, v = 0, debug = 0, dns = 1, lose = 0;
72// u_int32_t min = ~0, max = 0;
73 output_t output = OUT_CIDR;
74
75 progname = argv[0];
76 initerrors(progname, 0, 0); /* stderr, nostatus */
77 while((optc = getopt_long(argc, argv, "shoxdrvbincM:m:", longopts,
78 (int *) NULL((void*)0))) != EOF(-1)) switch(optc) {
79 case 'h': h = 1; break;
80 case 'v': v++; break;
81 case 'n': dns = 0; break;
82// case 'M': max = mspectou32(optarg); break;
83// case 'm': min = mspectou32(optarg); break;
84 case 'd':
85 initerrors(NULL((void*)0), -1, 1); /* showstatus */
86 debug = 1;
87 break;
88 case 's': output = OUT_STD; break;
89 case 'c': output = OUT_CIDR; break;
90 case 'i': output = OUT_CISCO; break;
91 case 'r': output = OUT_RANGE; break;
92 case 'x': output = OUT_HEX; break;
93 case 'o': output = OUT_OCTAL; break;
94 case 'b': output = OUT_BINARY; break;
95 default: lose = 1; break;
96 }
97 if(v) {
98 if(v == 1) fprintf(stderrstderr, "%s\n", version);
99 else fprintf(stderrstderr, "%s, %s\n", version, vversion);
100 if(!h) exit(0);
101 }
102 if(h) {
103 fprintf(stderrstderr,
104 "This is netmask, an address netmask generation utility\n"
105 "Usage: %s spec [spec ...]\n"
106 " -h, --help\t\t\tPrint a summary of the options\n"
107 " -v, --version\t\t\tPrint the version number\n"
108 " -d, --debug\t\t\tPrint status/progress information\n"
109 " -s, --standard\t\tOutput address/netmask pairs\n"
110 " -c, --cidr\t\t\tOutput CIDR format address lists\n"
111 " -i, --cisco\t\t\tOutput Cisco style address lists\n"
112 " -r, --range\t\t\tOutput ip address ranges\n"
113 " -x, --hex\t\t\tOutput address/netmask pairs in hex\n"
114 " -o, --octal\t\t\tOutput address/netmask pairs in octal\n"
115 " -b, --binary\t\t\tOutput address/netmask pairs in binary\n"
116 " -n, --nodns\t\t\tDisable DNS lookups for addresses\n"
117// " -M, --max mask\t\tLimit maximum mask size\n"
118// " -m, --min mask\t\tLimit minimum mask size (drop small ranges)\n"
119 "Definitions:\n"
120 " a spec can be any of:\n"
121 " address\n"
122 " address:address\n"
123 " address:+address\n"
124 " address/mask\n"
125 " an address can be any of:\n"
126 " N\t\tdecimal number\n"
127 " 0N\t\toctal number\n"
128 " 0xN\t\thex number\n"
129 " N.N.N.N\tdotted quad\n"
130 " hostname\tdns domain name\n"
131 " a mask is the number of bits set to one from the left\n", progname);
132 exit(0);
133 }
134 if(lose || optind == argc) {
135 fprintf(stderrstderr, usage, progname);
136 exit(1);
137 }
138 while(optind < argc) spectoaml(argv[optind++], dns);
139 display(output);
140 return(0);
141}
142
143/**************************************
144 * PART I - Read input *
145 **************************************/
146
147static u_int32_t aspectou32(char *, int);
148static int rangetoaml(u_int32_t, u_int32_t);
149static int strtou32(u_int32_t *, char *);
150#ifndef HAVE_STRTOUL1
151static u_int32_t strtoul(const char *nptr, char **endptr, int base);
152#endif
153
154/* spectoaml adds a spec to the aml.
155 * deals with:
156 * "address"
157 * "address:address"
158 * "address:+address"
159 * "address/mask" */
160int spectoaml(char *addrspec, int dns) {
161 char *sep;
162 u_int32_t addr;
163
164 if((sep = strchr(addrspec, ':')(__extension__ (__builtin_constant_p (':') && !__builtin_constant_p
(addrspec) && (':') == '\0' ? (char *) __rawmemchr (
addrspec, ':') : __builtin_strchr (addrspec, ':')))
) != NULL((void*)0)) { /* range */
165 u_int32_t addr2;
166
167 *sep++ = '\0';
168 addr = aspectou32(addrspec, dns);
169 if(*sep == '+') {
170 sep++;
171 addr2 = addr;
172 } else addr2 = 0;
173 addr2 += aspectou32(sep, dns);
174 rangetoaml(addr, addr2);
175 } else if((sep = strchr(addrspec, '/')(__extension__ (__builtin_constant_p ('/') && !__builtin_constant_p
(addrspec) && ('/') == '\0' ? (char *) __rawmemchr (
addrspec, '/') : __builtin_strchr (addrspec, '/')))
) != NULL((void*)0)) { /* mask */
176 u_int32_t mask;
177
178 *sep++ = '\0';
179 addr = aspectou32(addrspec, dns);
180 mask = mspectou32(sep);
181 addtoaml(addr, mask);
182 } else { /* host */
183 addr = aspectou32(addrspec, dns);
184 addtoaml(addr, ~0);
185 }
186 return(0);
187}
188/* aspectou32 should convert the address portion of a spec...
189 * "base10"
190 * "0base8"
191 * "0xbase16"
192 * "hostname"
193 * "address" */
194static u_int32_t aspectou32(char *astr, int dns) {
195 u_int32_t addr;
196 struct hostent *h;
197 struct in_addr s;
198
199 if(strtou32(&addr, astr));
200 else if(dns && ((h = gethostbyname(astr)) != NULL((void*)0)))
201 addr = ntohl(*((u_int32_t *)h->h_addr_list[0]))(__extension__ ({ unsigned int __v, __x = (*((u_int32_t *)h->
h_addr_list[0])); if (__builtin_constant_p (__x)) __v = ((((__x
) & 0xff000000) >> 24) | (((__x) & 0x00ff0000) >>
8) | (((__x) & 0x0000ff00) << 8) | (((__x) & 0x000000ff
) << 24)); else __asm__ ("bswap %0" : "=r" (__v) : "0" (
__x)); __v; }))
;
202 else if(inet_aton(astr, &s))
203 addr = ntohl(s.s_addr)(__extension__ ({ unsigned int __v, __x = (s.s_addr); if (__builtin_constant_p
(__x)) __v = ((((__x) & 0xff000000) >> 24) | (((__x
) & 0x00ff0000) >> 8) | (((__x) & 0x0000ff00) <<
8) | (((__x) & 0x000000ff) << 24)); else __asm__ (
"bswap %0" : "=r" (__v) : "0" (__x)); __v; }))
;
204 else panic("unable to parse \"%s\"", astr);
205 return(addr);
206}
207/* mspectou32 should convert the mask portion of a spec...
208 * "base10"
209 * "0base8"
210 * "0xbase16"
211 * "address" */
212static u_int32_t mspectou32(char *mstr) {
213 u_int32_t mask = 0, num;
214 struct in_addr s;
215
216 if(strtou32(&num, mstr)) mask = num ? ~0 << (32 - num) : num;
217 else if(inet_aton(mstr, &s)) {
218 mask = ntohl(s.s_addr)(__extension__ ({ unsigned int __v, __x = (s.s_addr); if (__builtin_constant_p
(__x)) __v = ((((__x) & 0xff000000) >> 24) | (((__x
) & 0x00ff0000) >> 8) | (((__x) & 0x0000ff00) <<
8) | (((__x) & 0x000000ff) << 24)); else __asm__ (
"bswap %0" : "=r" (__v) : "0" (__x)); __v; }))
;
219 for(num = ~mask; num & 1; num >>= 1);
220 if(num) {
221 for(num = mask; num & 1; num >>= 1);
222 if(num) panic("invalid mask 0x%08x from \"%s\"", mask, mstr);
223 mask = ~mask;
224 }
225 } else panic("unable to parse \"%s\"", mstr);
226 return(mask);
227}
228/* strtou32 shuld take an int pointer and a string looking like...
229 * "base10"
230 * "0base8"
231 * "0xbase16"
232 * and write the value as an unsigned 32 bit int
233 * returning true on success and false on failure */
234static int strtou32(u_int32_t *num, char *istr) {
235 u_int32_t value, base;
236 char *str, *endp;
237
238 if(istr == NULL((void*)0) || *istr == '\0') return(0);
239 if(istr[0] == '0' && istr[1]) {
240 if(istr[1] == 'x' && istr[2]) {
241 base = 16;
242 str = istr + 2;
243 } else {
244 base = 8;
245 str = istr + 1;
246 }
247 } else {
248 base = 10;
249 str = istr;
250 }
251 value = strtoul(str, &endp, base);
252 if(*endp != '\0') return(0);
253 *num = value;
254 return(1);
255}
256/* range to aml should take two addresses
257 * and add the shortest list of address/mask pairs between them */
258static int rangetoaml(u_int32_t low, u_int32_t high) {
259 u_int32_t i, j, lxh;
260
261 if(low > high) {
262 i = low;
263 low = high;
264 high = i;
265 }
266 for(lxh = i = low ^ high; i & 1; i >>= 1);
267 if(i == 0 && (low | lxh) == high) addtoaml(low, ~(high - low));
268 else {
269 for(i = lxh, j = 0; i >> 1; j++) i >>= 1;
270 i <<= j;
271 i = ~(i - 1) & high;
272 rangetoaml(low, i - 1);
273 rangetoaml(i, high);
274 }
275 return(0);
276}
277#ifndef HAVE_STRTOUL1
278#warning no ISO 9899 strtoul()? enabling sub-optimal workaround.
279static u_int32_t strtoul(const char *nptr, char **endptr, int base) {
280 char *fmt;
281 u_int32_t val;
282
283 switch(base) {
284 case 8: fmt = "%lo"; break;
285 case 10: fmt = "%lu"; break;
286 case 16: fmt = "%lx"; break;
287 }
288 if(sscanf(nptr, fmt, &val) > 0) *endptr = "";
289 else *endptr = nptr;
290 return(val);
291}
292#endif
293
294/**************************************
295 * PART II - List management *
296 **************************************/
297
298static int optimize(void);
299
300/* addtoaml takes an address and mask
301 * and adds it to the list
302 * note: it's a little bigger than it needs to be,
303 * but it's very modest about memory use
304 * and efficient enough considering it's use in optimize() */
305int addtoaml(u_int32_t addr, u_int32_t mask) {
306 int neta = addr & mask;
307 char first = 0;
308 struct addrmask *cur = aml, *lst = NULL((void*)0),
1
'lst' initialized to a null pointer value
309 *src = NULL((void*)0), *dst = NULL((void*)0), *old = NULL((void*)0);
310
311 if(aml == NULL((void*)0) || aml->mask > mask ||
2
Assuming 'aml' is not equal to null
312 (aml->mask == mask && aml->neta > neta)) first = 1;
313 else {
314 for(cur = aml; cur && (cur->mask < mask ||
315 (cur->mask == mask && cur->neta <= neta)); lst = cur, cur = cur->next)
316 if(cur->neta == (neta & cur->mask)) {
317 status("skip %08x/%08x (%08x/%08x exists)",
318 neta, mask, cur->neta, cur->mask);
319 return(0);
320 }
321 dst = lst;
322 }
323 while(cur) {
3
Loop condition is true. Entering loop body
5
Loop condition is false. Execution continues on line 340
324 if(neta == (cur->neta & mask)) {
4
Taking false branch
325 status("pull %08x/%08x (%08x/%08x added)",
326 cur->neta, cur->mask, neta, mask);
327 old = cur;
328 cur = cur->next;
329 if(old->prev) old->prev->next = old->next;
330 if(old->next) old->next->prev = old->prev;
331 if(aml == old) aml = cur; // suggested by Erik Gavert <erik@jsdata.se>
332 if(!old->prev && !old->next) {
333 aml = cur = NULL((void*)0);
334 first = 1;
335 }
336 if(!src) src = old;
337 else free(old);
338 } else cur = cur->next;
339 }
340 if(!src && (src = (struct addrmask *)malloc(sizeof(struct addrmask)))
6
Taking false branch
341 == NULL((void*)0)) panic("malloc failure");
342 src->neta = neta;
343 src->mask = mask;
344 if(first) {
7
Taking false branch
345 status("add first {%08x/%08x}%08x/%08x",
346 neta, mask, aml?aml->neta:0, aml?aml->mask:0);
347 src->prev = NULL((void*)0);
348 src->next = aml;
349 if(aml) aml->prev = src;
350 aml = src;
351 } else if(dst) {
8
Taking false branch
352 status("add middle %08x/%08x{%08x/%08x}%08x/%08x",
353 dst->neta, dst->mask,
354 neta, mask,
355 dst->next?dst->next->neta:0, dst->next?dst->next->mask:0);
356 src->prev = dst;
357 src->next = dst->next;
358 dst->next = src;
359 if(src->next) src->next->prev = src;
360 } else {
361 status("add last %08x/%08x{%08x/%08x}",
362 lst->neta, lst->mask, neta, mask);
9
Access to field 'neta' results in a dereference of a null pointer (loaded from variable 'lst')
363 src->prev = lst;
364 src->next = NULL((void*)0);
365 lst->next = src;
366 }
367 while(optimize());
368 return(0);
369}
370
371/* optimize - joins two AMs that can be expressed by a larger mask. */
372static int optimize(void) {
373 struct addrmask *cur;
374
375 for(cur = aml; cur->next; cur = cur->next)
376 if(cur->mask == cur->next->mask &&
377 cur->neta == (cur->next->neta & (cur->mask << 1))) {
378 addtoaml(cur->neta, cur->mask << 1);
379 return(1);
380 }
381 return(0);
382}
383
384/**************************************
385 * PART III - Output formatting *
386 **************************************/
387
388static int dispcidr(struct addrmask *);
389static int dispstd(struct addrmask *);
390static int dispcisco(struct addrmask *);
391static int disprange(struct addrmask *);
392static int disphex(struct addrmask *);
393static int dispoctal(struct addrmask *);
394static int dispbinary(struct addrmask *);
395
396/* display - shows the aml in a format specified by style
397 * it destroys the list as it sorts */
398int display(output_t style) {
399 struct addrmask *am, *list;
400 int (*disp)(struct addrmask *) = NULL((void*)0);
401
402 switch(style) {
403 case OUT_STD: disp = &dispstd; break;
404 case OUT_CIDR: disp = &dispcidr; break;
405 case OUT_CISCO: disp = &dispcisco; break;
406 case OUT_RANGE: disp = &disprange; break;
407 case OUT_HEX: disp = &disphex; break;
408 case OUT_OCTAL: disp = &dispoctal; break;
409 case OUT_BINARY: disp = &dispbinary; break;
410 default: panic("memfrob() apparently called on code segment");
411 }
412 while(aml) {
413 am = NULL((void*)0);
414 for(list = aml; list; list = list->next)
415 if(!am || am->neta > list->neta) am = list;
416 if(am->next) am->next->prev = am->prev;
417 if(am->prev) am->prev->next = am->next;
418 else aml = am->next;
419 disp(am);
420 free(am);
421 }
422 return(0);
423}
424
425static int dispcidr(struct addrmask *am) {
426 u_int32_t mask;
427 int ctr = 0;
428
429 for(mask = am->mask; mask; mask <<= 1) ctr++;
430 printf("%15s/%d\n", inet_ntoa((struct in_addr){htonl(am->neta)(__extension__ ({ unsigned int __v, __x = (am->neta); if (
__builtin_constant_p (__x)) __v = ((((__x) & 0xff000000) >>
24) | (((__x) & 0x00ff0000) >> 8) | (((__x) & 0x0000ff00
) << 8) | (((__x) & 0x000000ff) << 24)); else
__asm__ ("bswap %0" : "=r" (__v) : "0" (__x)); __v; }))
}), ctr);
431 return(0);
432}
433static int dispstd(struct addrmask *am) {
434 char buf[32];
435
436 sprintf(buf, "%15s/", inet_ntoa((struct in_addr){htonl(am->neta)(__extension__ ({ unsigned int __v, __x = (am->neta); if (
__builtin_constant_p (__x)) __v = ((((__x) & 0xff000000) >>
24) | (((__x) & 0x00ff0000) >> 8) | (((__x) & 0x0000ff00
) << 8) | (((__x) & 0x000000ff) << 24)); else
__asm__ ("bswap %0" : "=r" (__v) : "0" (__x)); __v; }))
}));
437 sprintf(buf + 16, "%-15s", inet_ntoa((struct in_addr){htonl(am->mask)(__extension__ ({ unsigned int __v, __x = (am->mask); if (
__builtin_constant_p (__x)) __v = ((((__x) & 0xff000000) >>
24) | (((__x) & 0x00ff0000) >> 8) | (((__x) & 0x0000ff00
) << 8) | (((__x) & 0x000000ff) << 24)); else
__asm__ ("bswap %0" : "=r" (__v) : "0" (__x)); __v; }))
}));
438 puts(buf);
439 return(0);
440}
441static int dispcisco(struct addrmask *am) {
442 char buf[32];
443
444 sprintf(buf, "%15s ", inet_ntoa((struct in_addr){htonl(am->neta)(__extension__ ({ unsigned int __v, __x = (am->neta); if (
__builtin_constant_p (__x)) __v = ((((__x) & 0xff000000) >>
24) | (((__x) & 0x00ff0000) >> 8) | (((__x) & 0x0000ff00
) << 8) | (((__x) & 0x000000ff) << 24)); else
__asm__ ("bswap %0" : "=r" (__v) : "0" (__x)); __v; }))
}));
445 sprintf(buf + 16, "%-15s", inet_ntoa((struct in_addr){htonl(~am->mask)(__extension__ ({ unsigned int __v, __x = (~am->mask); if (
__builtin_constant_p (__x)) __v = ((((__x) & 0xff000000) >>
24) | (((__x) & 0x00ff0000) >> 8) | (((__x) & 0x0000ff00
) << 8) | (((__x) & 0x000000ff) << 24)); else
__asm__ ("bswap %0" : "=r" (__v) : "0" (__x)); __v; }))
}));
446 puts(buf);
447 return(0);
448}
449static int disprange(struct addrmask *am) {
450 char buf[80];
451 u_int32_t range = ~am->mask + 1;
452
453 sprintf(buf, "%15s-", inet_ntoa((struct in_addr){htonl(am->neta)(__extension__ ({ unsigned int __v, __x = (am->neta); if (
__builtin_constant_p (__x)) __v = ((((__x) & 0xff000000) >>
24) | (((__x) & 0x00ff0000) >> 8) | (((__x) & 0x0000ff00
) << 8) | (((__x) & 0x000000ff) << 24)); else
__asm__ ("bswap %0" : "=r" (__v) : "0" (__x)); __v; }))
}));
454 sprintf(buf + 16, "%-15s (%u)",
455 inet_ntoa((struct in_addr){htonl(am->neta + range - 1)(__extension__ ({ unsigned int __v, __x = (am->neta + range
- 1); if (__builtin_constant_p (__x)) __v = ((((__x) & 0xff000000
) >> 24) | (((__x) & 0x00ff0000) >> 8) | (((__x
) & 0x0000ff00) << 8) | (((__x) & 0x000000ff) <<
24)); else __asm__ ("bswap %0" : "=r" (__v) : "0" (__x)); __v
; }))
}), range);
456 puts(buf);
457 return(0);
458}
459static int disphex(struct addrmask *am) {
460 printf("0x%08x/0x%08x\n", am->neta, am->mask);
461 return(0);
462}
463static int dispoctal(struct addrmask *am) {
464 printf("0%10o/0%10o\n", am->neta, am->mask);
465 return(0);
466}
467static int dispbinary(struct addrmask *am) {
468 char abuf[36], mbuf[36];
469 int i, j;
470
471 for(i = 0; i < 32; i++) {
472 j = 34 - (int)(i * 9 / 8); /* array index skips every 9th element */
473 abuf[j] = am->neta & 1 ? '1' : '0';
474 mbuf[j] = am->mask & 1 ? '1' : '0';
475 am->neta >>= 1;
476 am->mask >>= 1;
477 }
478 abuf[8] = abuf[17] = abuf[26] = mbuf[8] = mbuf[17] = mbuf[26] = ' ';
479 abuf[35] = mbuf[35] = '\0';
480 printf("%s / %s\n", abuf, mbuf);
481 return(0);
482}