xref: /netbsd/lib/libform/type_ipv4.c (revision bf9ec67e)
1 /*	$NetBSD: type_ipv4.c,v 1.6 2001/06/13 10:45:59 wiz 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 <string.h>
33 #include <stdlib.h>
34 #include <ctype.h>
35 #include <errno.h>
36 #include <stdlib.h>
37 #include <limits.h>
38 #include "form.h"
39 #include "internals.h"
40 
41 /*
42  * The IP v4 address type handling.
43  */
44 
45 /*
46  * define the styles of address we can have, they are:
47  *    FORMI_DOTTED_QUAD    address of form aaa.bbb.ccc.ddd
48  *    FORMI_HEX            address of form 0xaabbccdd
49  *    FORMI_CLASSLESS      address of form aaa.bbb.ccc.ddd/ee
50  */
51 #define FORMI_DOTTED_QUAD  0
52 #define FORMI_HEX          1
53 #define FORMI_CLASSLESS    2
54 
55 /*
56  * Check the contents of the field buffer are a valid IPv4 address only.
57  */
58 static int
59 ipv4_check_field(FIELD *field, char *args)
60 {
61 	char *buf, *buf1, *keeper, *p, *slash;
62 	unsigned int vals[4], style, start, mask;
63 	unsigned long hex_val, working;
64 	int i;
65 
66 	if (args == NULL)
67 		return FALSE;
68 
69 	if (asprintf(&keeper, "%s", args) < 0)
70 		return FALSE;
71 
72 #ifdef DEBUG
73 	fprintf(dbg, "ipv4_check_field: enter with args of %s\n", keeper);
74 #endif
75 	style = FORMI_DOTTED_QUAD;
76 	buf = keeper;
77 
78 	if ((slash = index(buf, '/')) != NULL)
79 		style = FORMI_CLASSLESS;
80 	else {
81 		start = _formi_skip_blanks(buf, 0);
82 		if ((buf[start] != '\0') && (buf[start + 1] != '\0') &&
83 		    (buf[start] == '0') && ((buf[start + 1] == 'x') ||
84 					    (buf[start + 1] == 'X')))
85 			style = FORMI_HEX;
86 	}
87 
88 	switch (style) {
89 	case FORMI_CLASSLESS:
90 		*slash = '\0';
91 		slash++;
92 		mask = atoi(slash);
93 		if (mask > 32)
94 			goto FAIL;
95 		  /* FALLTHROUGH */
96 
97 	case FORMI_DOTTED_QUAD:
98 		for (i = 0; i < 4; i++) {
99 			p = strsep(&buf, ".");
100 			if ((p == NULL) || (*p == '\0'))
101 				goto FAIL;
102 			vals[i] = atoi(p);
103 			if (vals[i] > 255)
104 				goto FAIL;
105 		}
106 		break;
107 
108 
109 	case FORMI_HEX:
110 		hex_val = strtoul(buf, NULL, 16);
111 		if ((hex_val == ULONG_MAX) && (errno == ERANGE))
112 			goto FAIL;
113 
114 		working = hex_val;
115 		for (i = 3; i >= 0; i--) {
116 			vals[i] = (unsigned int)(working & 0xffUL);
117 			working = working >> 8;
118 		}
119 		break;
120 
121 	}
122 
123 	free(keeper);
124 
125 	buf1 = NULL;
126 
127 	switch (style) {
128 	case FORMI_DOTTED_QUAD:
129 		if (asprintf(&buf, "%d.%d.%d.%d", vals[0], vals[1], vals[2],
130 			     vals[3]) < 0)
131 			return FALSE;
132 		if (asprintf(&buf1, "%d.%d.%d.%d", vals[0], vals[1],
133 			     vals[2], vals[3]) < 0)
134 			return FALSE;
135 		break;
136 
137 	case FORMI_CLASSLESS:
138 		if (asprintf(&buf, "%d.%d.%d.%d/%d", vals[0], vals[1],
139 			     vals[2], vals[3], mask) < 0)
140 			return FALSE;
141 		if (asprintf(&buf1, "%d.%d.%d.%d", vals[0], vals[1],
142 			     vals[2], vals[3]) < 0)
143 			return FALSE;
144 		break;
145 
146 	case FORMI_HEX:
147 		if (asprintf(&buf, "0x%.8lx", hex_val) < 0)
148 			return FALSE;
149 		if (asprintf(&buf1, "%d.%d.%d.%d", vals[0], vals[1],
150 			     vals[2], vals[3]) < 0)
151 			return FALSE;
152 		break;
153 	}
154 
155 	  /* re-set the field buffer to be the reformatted IPv4 address */
156 	set_field_buffer(field, 0, buf);
157 
158 	  /*
159 	   * Set the field buffer 1 to the dotted quad format regardless
160 	   * of the input format, only if buffer 1 exists.
161 	   */
162 	if (field->nbuf > 1)
163 		set_field_buffer(field, 1, buf1);
164 
165 #ifdef DEBUG
166 	fprintf(dbg, "ipv4_check_field: buf0 set to %s\n", buf);
167 	fprintf(dbg, "ipv4_check_field: buf1 set to %s\n", buf1);
168 #endif
169 	free(buf);
170 	free(buf1);
171 
172 	return TRUE;
173 
174 	  /* bail out point if we got a bad entry */
175   FAIL:
176 	free(keeper);
177 	return FALSE;
178 
179 }
180 
181 /*
182  * Check the given character is numeric, return TRUE if it is.
183  */
184 static int
185 ipv4_check_char(/* ARGSUSED1 */ int c, char *args)
186 {
187 	return (isxdigit(c) || (c == '.') || (tolower(c) == 'x') ||
188 		(c == '/'))? TRUE : FALSE;
189 }
190 
191 static FIELDTYPE builtin_ipv4 = {
192 	_TYPE_IS_BUILTIN,                   /* flags */
193 	0,                                  /* refcount */
194 	NULL,                               /* link */
195 	NULL,                               /* make_args */
196 	NULL,                               /* copy_args */
197 	NULL,                               /* free_args */
198 	ipv4_check_field,                   /* field_check */
199 	ipv4_check_char,                    /* char_check */
200 	NULL,                               /* next_choice */
201 	NULL                                /* prev_choice */
202 };
203 
204 FIELDTYPE *TYPE_IPV4 = &builtin_ipv4;
205 
206 
207