1/*	$NetBSD: type_ipv4.c,v 1.11 2016/03/09 19:47:13 christos Exp $	*/
2
3/*-
4 * Copyright (c) 1998-1999 Brett Lymn
5 *                         (blymn@baea.com.au, brett_lymn@yahoo.com.au)
6 * All rights reserved.
7 *
8 * This code has been donated to The NetBSD Foundation by the Author.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. The name of the author may not be used to endorse or promote products
16 *    derived from this software without specific prior written permission
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 *
30 */
31
32#include <sys/cdefs.h>
33__RCSID("$NetBSD: type_ipv4.c,v 1.11 2016/03/09 19:47:13 christos Exp $");
34
35#include <string.h>
36#include <stdlib.h>
37#include <ctype.h>
38#include <errno.h>
39#include <limits.h>
40#include "form.h"
41#include "internals.h"
42
43/*
44 * The IP v4 address type handling.
45 */
46
47/*
48 * define the styles of address we can have, they are:
49 *    FORMI_DOTTED_QUAD    address of form aaa.bbb.ccc.ddd
50 *    FORMI_HEX            address of form 0xaabbccdd
51 *    FORMI_CLASSLESS      address of form aaa.bbb.ccc.ddd/ee
52 */
53#define FORMI_DOTTED_QUAD  0
54#define FORMI_HEX          1
55#define FORMI_CLASSLESS    2
56
57/*
58 * Check the contents of the field buffer are a valid IPv4 address only.
59 */
60static int
61ipv4_check_field(FIELD *field, char *args)
62{
63	char *buf, *buf1, *keeper, *p, *slash;
64	unsigned int vals[4], style, start, mask;
65	unsigned long hex_val, working;
66	int i;
67
68	if (args == NULL)
69		return FALSE;
70
71	if (asprintf(&keeper, "%s", args) < 0)
72		return FALSE;
73
74#ifdef DEBUG
75	_formi_dbg_printf("%s: enter with args of %s\n", __func__, keeper);
76#endif
77	style = FORMI_DOTTED_QUAD;
78	buf = keeper;
79	hex_val = 0;
80	mask = 0;
81
82	if ((slash = index(buf, '/')) != NULL)
83		style = FORMI_CLASSLESS;
84	else {
85		start = _formi_skip_blanks(buf, 0);
86		if ((buf[start] != '\0') && (buf[start + 1] != '\0') &&
87		    (buf[start] == '0') && ((buf[start + 1] == 'x') ||
88					    (buf[start + 1] == 'X')))
89			style = FORMI_HEX;
90	}
91
92	switch (style) {
93	case FORMI_CLASSLESS:
94		*slash = '\0';
95		slash++;
96		mask = atoi(slash);
97		if (mask > 32)
98			goto FAIL;
99		  /* FALLTHROUGH */
100
101	case FORMI_DOTTED_QUAD:
102		for (i = 0; i < 4; i++) {
103			p = strsep(&buf, ".");
104			if ((p == NULL) || (*p == '\0'))
105				goto FAIL;
106			vals[i] = atoi(p);
107			if (vals[i] > 255)
108				goto FAIL;
109		}
110		break;
111
112
113	case FORMI_HEX:
114		errno = 0;
115		hex_val = strtoul(buf, NULL, 16);
116		if ((hex_val == ULONG_MAX) && (errno == ERANGE))
117			goto FAIL;
118
119		working = hex_val;
120		for (i = 3; i >= 0; i--) {
121			vals[i] = (unsigned int)(working & 0xffUL);
122			working = working >> 8;
123		}
124		break;
125
126	}
127
128	free(keeper);
129
130	buf1 = NULL;
131
132	switch (style) {
133	case FORMI_DOTTED_QUAD:
134		if (asprintf(&buf, "%d.%d.%d.%d", vals[0], vals[1], vals[2],
135			     vals[3]) < 0)
136			return FALSE;
137		if (asprintf(&buf1, "%d.%d.%d.%d", vals[0], vals[1],
138			     vals[2], vals[3]) < 0)
139			return FALSE;
140		break;
141
142	case FORMI_CLASSLESS:
143		if (asprintf(&buf, "%d.%d.%d.%d/%d", vals[0], vals[1],
144			     vals[2], vals[3], mask) < 0)
145			return FALSE;
146		if (asprintf(&buf1, "%d.%d.%d.%d", vals[0], vals[1],
147			     vals[2], vals[3]) < 0)
148			return FALSE;
149		break;
150
151	case FORMI_HEX:
152		if (asprintf(&buf, "0x%.8lx", hex_val) < 0)
153			return FALSE;
154		if (asprintf(&buf1, "%d.%d.%d.%d", vals[0], vals[1],
155			     vals[2], vals[3]) < 0)
156			return FALSE;
157		break;
158	}
159
160	  /* re-set the field buffer to be the reformatted IPv4 address */
161	set_field_buffer(field, 0, buf);
162
163	  /*
164	   * Set the field buffer 1 to the dotted quad format regardless
165	   * of the input format, only if buffer 1 exists.
166	   */
167	if (field->nbuf > 1)
168		set_field_buffer(field, 1, buf1);
169
170#ifdef DEBUG
171	_formi_dbg_printf("%s: buf0 set to %s\n", __func__, buf);
172	_formi_dbg_printf("%s: buf1 set to %s\n", __func__, buf1);
173#endif
174	free(buf);
175	free(buf1);
176
177	return TRUE;
178
179	  /* bail out point if we got a bad entry */
180  FAIL:
181	free(keeper);
182	return FALSE;
183
184}
185
186/*
187 * Check the given character is numeric, return TRUE if it is.
188 */
189static int
190ipv4_check_char(/* ARGSUSED1 */ int c, char *args)
191{
192	return (isxdigit(c) || (c == '.') || (tolower(c) == 'x') ||
193		(c == '/'))? TRUE : FALSE;
194}
195
196static FIELDTYPE builtin_ipv4 = {
197	_TYPE_IS_BUILTIN,                   /* flags */
198	0,                                  /* refcount */
199	NULL,                               /* link */
200	NULL,                               /* make_args */
201	NULL,                               /* copy_args */
202	NULL,                               /* free_args */
203	ipv4_check_field,                   /* field_check */
204	ipv4_check_char,                    /* char_check */
205	NULL,                               /* next_choice */
206	NULL                                /* prev_choice */
207};
208
209FIELDTYPE *TYPE_IPV4 = &builtin_ipv4;
210
211
212