diff --git a/socket/fmt_ip4.3 b/socket/fmt_ip4.3 index 9e32ffc..993ac53 100644 --- a/socket/fmt_ip4.3 +++ b/socket/fmt_ip4.3 @@ -24,4 +24,4 @@ contain every possible fmt_ip4 output plus \\0. char ip[4]; buf[fmt_ip4(buf,ip)]=0; .SH "SEE ALSO" -scan_ip4(3), ip6_fmt(3) +scan_ip4(3), fmt_ip6(3) diff --git a/socket/fmt_ip6.3 b/socket/fmt_ip6.3 index 76c3aac..d38a768 100644 --- a/socket/fmt_ip6.3 +++ b/socket/fmt_ip6.3 @@ -29,4 +29,4 @@ contain every possible fmt_ip6 output plus \\0. char ip[16]; buf[fmt_ip6(buf,ip)]=0; .SH "SEE ALSO" -scan_ip6(3), ip4_fmt(3) +scan_ip6(3), fmt_ip4(3) diff --git a/socket/scan_ip4.3 b/socket/scan_ip4.3 new file mode 100644 index 0000000..fd914f9 --- /dev/null +++ b/socket/scan_ip4.3 @@ -0,0 +1,26 @@ +.TH scan_ip4 3 +.SH NAME +scan_ip4 \- parse an IPv4 number in dotted-decimal notation +.SH SYNTAX +.B #include + +int \fBscan_ip4\fP(const char *\fIsrc\fR,char \fIip\fR[4]); +.SH DESCRIPTION +scan_ip4 parses an IPv4 number in dotted-decimal ASCII representation +from \fIsrc\fR and writes the result into \fIip\fR. It returns the +number of bytes read from \fIsrc\fR or 0 if the parsing failed. + +Unlike many other IP parsing routines, scan_ip4 does not recognize octal +(like \fB0177.0.0.1\fR) or hexadecimal numbers (like \fB0x7f000001\fR). +.SH EXAMPLE +#include +.br +#include + + char buf[]="160.45.40.10"; + char ip[4]; + if (scan_ip4(buf,ip) != str_len(buf)) + parse_error(); + +.SH "SEE ALSO" +fmt_ip4(3), scan_ip6(3) diff --git a/socket/scan_ip4.c b/socket/scan_ip4.c new file mode 100644 index 0000000..18f4394 --- /dev/null +++ b/socket/scan_ip4.c @@ -0,0 +1,19 @@ +#include "scan.h" +#include "ip4.h" + +unsigned int scan_ip4(const char *s,char ip[4]) +{ + unsigned int len; + unsigned long u; + int i; + + len = 0; + for (i=0; i<4; ++i) { + register unsigned int j; + len+=(j=scan_ulong(s,&u))+1; + if (!j) return 0; + ip[i]=u; s+=j; + if (*s!='.') return 0; ++s; + } + return len-1; +} diff --git a/socket/scan_ip6.3 b/socket/scan_ip6.3 new file mode 100644 index 0000000..6694fd0 --- /dev/null +++ b/socket/scan_ip6.3 @@ -0,0 +1,35 @@ +.TH scan_ip6 3 +.SH NAME +scan_ip6 \- parse an IPv6 number in ASCII representation +.SH SYNTAX +.B #include + +int \fBscan_ip6\fP(const char *\fIsrc\fR,char \fIip\fR[16]); +.SH DESCRIPTION +scan_ip6 parses an IPv6 number in RFC1884 ASCII representation +from \fIsrc\fR and writes the result into \fIip\fR. It returns the +number of bytes read from \fIsrc\fR or 0 if the parsing failed. + +scan_ip6 accepts upper and lower case hex letters, it understands "::" +compression and partial IPv4 addresses as in "::FFFF:129.144.52.38". + +To allow transparent usage of IPv4 in IPv6 applications, scan_ip6 also +understands IPv4 addresses in dotted-decimal notation and will return +an IPv4-mapped IPv6 address (i.e. "127.0.0.1" will be parsed as +"::FFFF:127.0.0.1". + +Unlike many other IP parsing routines, scan_ip6 does not recognize octal +(like \fB0177.0.0.1\fR) or hexadecimal numbers (like \fB0x7f000001\fR) +in the IPv4 part. +.SH EXAMPLE +#include +.br +#include + + char buf[]="::1"; + char ip[16]; + if (scan_ip6(buf,ip) != str_len(buf)) + parse_error(); + +.SH "SEE ALSO" +fmt_ip6(3), scan_ip4(3) diff --git a/socket/scan_ip6.c b/socket/scan_ip6.c new file mode 100644 index 0000000..3598fc6 --- /dev/null +++ b/socket/scan_ip6.c @@ -0,0 +1,109 @@ +#include "scan.h" +#include "ip4.h" +#include "ip6.h" + +/* + * IPv6 addresses are really ugly to parse. + * Syntax: (h = hex digit) + * 1. hhhh:hhhh:hhhh:hhhh:hhhh:hhhh:hhhh:hhhh + * 2. any number of 0000 may be abbreviated as "::", but only once + * 3. The last two words may be written as IPv4 address + */ + +unsigned int scan_ip6(const char *s,char ip[16]) +{ + unsigned int i; + unsigned int len=0; + unsigned long u; + + char suffix[16]; + int prefixlen=0; + int suffixlen=0; + + for (i=0; i<16; i++) ip[i]=0; + + for (;;) { + if (*s == ':') { + len++; + if (s[1] == ':') { /* Found "::", skip to part 2 */ + s+=2; + len++; + break; + } + s++; + } + i = scan_xlong(s,&u); + if (!i) return 0; + if (prefixlen==12 && s[i]=='.') { + /* the last 4 bytes may be written as IPv4 address */ + i=ip4_scan(s,ip+12); + if (i) + return i+len; + else + return 0; + } + ip[prefixlen++] = (u >> 8); + ip[prefixlen++] = (u & 255); + s += i; len += i; + if (prefixlen==16) + return len; + } + +/* part 2, after "::" */ + for (;;) { + if (*s == ':') { + if (suffixlen==0) + break; + s++; + len++; + } else if (suffixlen!=0) + break; + i = scan_xlong(s,&u); + if (!i) { + len--; + break; + } + if (suffixlen+prefixlen<=12 && s[i]=='.') { + int j=ip4_scan(s,suffix+suffixlen); + if (j) { + suffixlen+=4; + len+=j; + break; + } else + prefixlen=12-suffixlen; /* make end-of-loop test true */ + } + suffix[suffixlen++] = (u >> 8); + suffix[suffixlen++] = (u & 255); + s += i; len += i; + if (prefixlen+suffixlen==16) + break; + } + for (i=0; i='0' && c<='9') + return c-'0'; + else if (c>='A' && c<='F') + return c-'A'+10; + else if (c>='a' && c<='f') + return c-'a'+10; + return -1; +} + +unsigned int scan_ip6_flat(const char *s,char ip[16]) +{ + int i; + for (i=0; i<16; i++) { + int tmp; + tmp=fromhex(*s++); + if (tmp<0) return 0; + ip[i]=tmp << 4; + tmp=fromhex(*s++); + if (tmp<0) return 0; + ip[i]+=tmp; + } + return 32; +}