1/* 2 * This program is free software; you can redistribute it and/or 3 * modify it under the terms of the GNU General Public License as 4 * published by the Free Software Foundation; either version 2 of 5 * the License, or (at your option) any later version. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program; if not, write to the Free Software 14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 15 * MA 02111-1307 USA 16 */ 17/* 18 * Part of Very Secure FTPd 19 * Licence: GPL v2 20 * Author: Chris Evans 21 * ipaddrparse.c 22 * 23 * A routine to parse ip addresses. I'm paranoid and don't want to use 24 * inet_pton. 25 */ 26 27#include "ipaddrparse.h" 28#include "sysutil.h" 29#include "str.h" 30 31static int ipv6_parse_main(struct mystr* p_out_str, 32 const struct mystr* p_in_str); 33static int ipv6_parse_hex(struct mystr* p_out_str, 34 const struct mystr* p_in_str); 35static int ipv4_parse_dotquad(struct mystr* p_out_str, 36 const struct mystr* p_in_str); 37 38const unsigned char* 39vsf_sysutil_parse_ipv6(const struct mystr* p_str) 40{ 41 static struct mystr s_ret; 42 static struct mystr s_rhs_ret; 43 static struct mystr s_lhs_str; 44 static struct mystr s_rhs_str; 45 unsigned int lhs_len; 46 unsigned int rhs_len; 47 str_empty(&s_ret); 48 str_empty(&s_rhs_ret); 49 str_copy(&s_lhs_str, p_str); 50 str_split_text(&s_lhs_str, &s_rhs_str, "::"); 51 if (!ipv6_parse_main(&s_ret, &s_lhs_str)) 52 { 53 return 0; 54 } 55 if (!ipv6_parse_main(&s_rhs_ret, &s_rhs_str)) 56 { 57 return 0; 58 } 59 lhs_len = str_getlen(&s_ret); 60 rhs_len = str_getlen(&s_rhs_ret); 61 if (lhs_len + rhs_len > 16) 62 { 63 return 0; 64 } 65 if (rhs_len > 0) 66 { 67 unsigned int add_nulls = 16 - (lhs_len + rhs_len); 68 while (add_nulls--) 69 { 70 str_append_char(&s_ret, '\0'); 71 } 72 str_append_str(&s_ret, &s_rhs_ret); 73 } 74 return (unsigned char*)str_getbuf(&s_ret); 75} 76 77const unsigned char* 78vsf_sysutil_parse_ipv4(const struct mystr* p_str) 79{ 80 static unsigned char items[4]; 81 return vsf_sysutil_parse_uchar_string_sep(p_str, '.', items, sizeof(items)); 82} 83 84const unsigned char* 85vsf_sysutil_parse_uchar_string_sep( 86 const struct mystr* p_str, char sep, unsigned char* p_items, 87 unsigned int items) 88{ 89 static struct mystr s_tmp_str; 90 unsigned int i; 91 str_copy(&s_tmp_str, p_str); 92 for (i=0; i<items; i++) 93 { 94 static struct mystr s_rhs_sep_str; 95 int this_number; 96 /* This puts a single separator delimited field in tmp_str */ 97 str_split_char(&s_tmp_str, &s_rhs_sep_str, sep); 98 /* Sanity - check for too many or two few dots! */ 99 if ( (i < (items-1) && str_isempty(&s_rhs_sep_str)) || 100 (i == (items-1) && !str_isempty(&s_rhs_sep_str))) 101 { 102 return 0; 103 } 104 this_number = str_atoi(&s_tmp_str); 105 if (this_number < 0 || this_number > 255) 106 { 107 return 0; 108 } 109 /* If this truncates from int to uchar, we don't care */ 110 p_items[i] = (unsigned char) this_number; 111 /* The right hand side of the comma now becomes the new string to 112 * breakdown 113 */ 114 str_copy(&s_tmp_str, &s_rhs_sep_str); 115 } 116 return p_items; 117} 118 119static int 120ipv6_parse_main(struct mystr* p_out_str, const struct mystr* p_in_str) 121{ 122 static struct mystr s_lhs_str; 123 static struct mystr s_rhs_str; 124 struct str_locate_result loc_ret; 125 str_copy(&s_lhs_str, p_in_str); 126 while (!str_isempty(&s_lhs_str)) 127 { 128 str_split_char(&s_lhs_str, &s_rhs_str, ':'); 129 if (str_isempty(&s_lhs_str)) 130 { 131 return 0; 132 } 133 loc_ret = str_locate_char(&s_lhs_str, '.'); 134 if (loc_ret.found) 135 { 136 if (!ipv4_parse_dotquad(p_out_str, &s_lhs_str)) 137 { 138 return 0; 139 } 140 } 141 else if (!ipv6_parse_hex(p_out_str, &s_lhs_str)) 142 { 143 return 0; 144 } 145 str_copy(&s_lhs_str, &s_rhs_str); 146 } 147 return 1; 148} 149 150static int 151ipv6_parse_hex(struct mystr* p_out_str, const struct mystr* p_in_str) 152{ 153 unsigned int len = str_getlen(p_in_str); 154 unsigned int i; 155 unsigned int val = 0; 156 for (i=0; i<len; ++i) 157 { 158 int ch = vsf_sysutil_toupper(str_get_char_at(p_in_str, i)); 159 if (ch >= '0' && ch <= '9') 160 { 161 ch -= '0'; 162 } 163 else if (ch >= 'A' && ch <= 'F') 164 { 165 ch -= 'A'; 166 ch += 10; 167 } 168 else 169 { 170 return 0; 171 } 172 val <<= 4; 173 val |= ch; 174 if (val > 0xFFFF) 175 { 176 return 0; 177 } 178 } 179 str_append_char(p_out_str, (val >> 8)); 180 str_append_char(p_out_str, (val & 0xFF)); 181 return 1; 182} 183 184static int 185ipv4_parse_dotquad(struct mystr* p_out_str, const struct mystr* p_in_str) 186{ 187 unsigned int len = str_getlen(p_in_str); 188 unsigned int i; 189 unsigned int val = 0; 190 unsigned int final_val = 0; 191 int seen_char = 0; 192 int dots = 0; 193 for (i=0; i<len; ++i) 194 { 195 int ch = str_get_char_at(p_in_str, i); 196 if (ch == '.') 197 { 198 if (!seen_char || dots == 3) 199 { 200 return 0; 201 } 202 seen_char = 0; 203 dots++; 204 final_val <<= 8; 205 final_val |= val; 206 val = 0; 207 } 208 else if (ch >= '0' && ch <= '9') 209 { 210 ch -= '0'; 211 val *= 10; 212 val += ch; 213 if (val > 255) 214 { 215 return 0; 216 } 217 seen_char = 1; 218 } 219 else 220 { 221 return 0; 222 } 223 } 224 if (dots != 3 || !seen_char) 225 { 226 return 0; 227 } 228 final_val <<= 8; 229 final_val |= val; 230 str_append_char(p_out_str, (final_val >> 24)); 231 str_append_char(p_out_str, ((final_val >> 16) & 0xFF)); 232 str_append_char(p_out_str, ((final_val >> 8) & 0xFF)); 233 str_append_char(p_out_str, (final_val & 0xFF)); 234 return 1; 235} 236 237