Okay, I'm officially stumped.  Can someone lend me a clue as to what,
if anything, I'm doing wrong in the following scenario?

I was playing around with smtpd(8) configuration options the other
day, and tried to write an "accept" rule in smtpd.conf for an IPv6
subnet.  However, when I tried to verify the config I got an error:


s...@fw ~ $ grep 2001 /etc/mail/smtpd.conf
accept from 2001:470:8:1ee::/64 for all relay
s...@fw ~ $ smtpd -n
smtpd: inet_net_pton: Address family not supported by protocol family


I tracked down that error to /usr/src/usr.sbin/smtpd/parse.y, where in
a few places the code is passing AF_INET6 as the address family
argument to the function "inet_net_pton()" when it tries to parse the
address/subnet string as an IPv6 entity (seems logical to me).
However, in looking at /usr/src/lib/libc/net/inet_net_pton.c, that
function does not actually accept AF_INET6 as a valid address family:


int
inet_net_pton(int af, const char *src, void *dst, size_t size)
{
        switch (af) {
        case AF_INET:
                return (inet_net_pton_ipv4(src, dst, size));
        default:
                errno = EAFNOSUPPORT;
                return (-1);
        }
}


I looked around a bit and found that NetBSD does have code to handle
the AF_INET6 case, so I borrowed their code as a test (I guess it's
actually Paul Vixie's BIND code?), recompiled libc, and now 'smtpd -n'
says the configuration is OK.  Great...kind of.  I did have to change
the 'accept' rule above to add a zero at the end of the string in
order for it to pass inspection for whatever reason:


s...@bsd ~ $ grep 2001 /etc/mail/smtpd.conf
accept from 2001:470:8:1ee::/64 for all relay
s...@bsd ~ $ smtpd -n
smtpd: inet_net_pton: No such file or directory
[...]
s...@bsd ~ $ grep 2001 /etc/mail/smtpd.conf
accept from 2001:470:8:1ee::0/64 for all relay
s...@bsd ~ $ smtpd -n
configuration OK


Anyway, I started smtpd up again, did a quick test, and...it still failed:


s...@darwin ~ $ telnet bsd.crosse.org 25
Trying 2001:470:8:1ee:20c:29ff:fe18:1984...
Connected to bsd.crosse.org.
Escape character is '^]'.
220 bsd.crosse.org ESMTP OpenSMTPD
helo darwin.crosse.org
250 bsd.crosse.org Hello darwin.crosse.org
[IPv6:2001:470:8:1ee:5ab0:35ff:fe78:c7a0], pleased to meet you
mail from:<[email protected]>
250 2.1.0 Sender ok
rcpt to:<[email protected]>
530 5.0.0 Recipient rejected: [email protected]
quit
221 2.0.0 bsd.crosse.org Closing connection
Connection closed by foreign host.


The smtpd debug output for the session looks like this:


s...@bsd /usr/src/usr.sbin/smtpd $ sudo smtpd -dv
startup [debug mode]
parent_send_config: configuring smtp
parent_send_config_client_certs: configuring smtp
parent_send_config_ruleset: reloading rules and maps
parent_enqueue_offline: path /offline/1272603601.j459NrpVLg
smtp_setup_events: listen on IPv6:2001:470:8:1ee:20c:29ff:fe18:1984
port 25 flags 0x0 cert "vic0"
smtp_setup_events: listen on 192.168.2.24 port 25 flags 0x0 cert "vic0"
smtp_setup_events: listen on IPv6:fe80:1::20c:29ff:fe18:1984 port 25
flags 0x0 cert "vic0"
smtp_setup_events: listen on IPv6:fe80:3::1 port 25 flags 0x0 cert "lo0"
smtp_setup_events: listen on IPv6:::1 port 25 flags 0x0 cert "lo0"
smtp_setup_events: listen on 127.0.0.1 port 25 flags 0x0 cert "lo0"
smtp: will accept at most 244 clients
offline message enqueued
session_pickup: greeting client
command: helo   args: darwin.crosse.org
command: mail from      args: <[email protected]>
session_rfc5321_mail_handler: sending notification to mfa
smtp: got imsg_mfa_mail/rcpt
smtp: imsg_queue_create_message returned
command: rcpt to        args: <[email protected]>
smtp: got imsg_mfa_mail/rcpt
1272604479.ozbOZIoTFKlNu1MN: from=<[email protected]>,
relay=darwin.crosse.org [IPv6:2001:470:8:1ee:5ab0:35ff:fe78:c7a0],
stat=LocalError (530 5.0.0 Recipient rejected: [email protected])
command: quit   args: (null)
session_destroy: killing client: 0x86ce1000


>From my admittedly very limited knowledge of using gdb, I think the
problem is in ruleset.c, in a function called
"ruleset_inet6_match()"--however, I've stared at the code now for an
hour or two and still have no idea what I'm looking at.  So, here's
the big question:  did I overlook something completely obvious and
have now gone off the deep end in searching for a bug that's not
there?  Any hints or suggestions are welcome.  I think I can say with
some level of confidence that this code-path will not work as-is since
OpenBSD's inet_net_pton() only accepts AF_INET as the address family
argument.  Adding the extra functions from NetBSD's code helped, but I
don't know enough about this stuff to know whether the four-odd
functions I added are "enough" or if they are really part of a much
larger undertaking.

Thanks for your time,

Seth

(conf, dmesg, and changes to libc follow)

Note:  this was all done with -current at some point or other.  The
dmesg below is from a VMware guest and shows a kernel from the 4/24
snapshot, but I've been playing with this stuff on a couple of
different machines (all either i386 or amd64).  The other one (real,
not virtual, and currently off) was fully up-to-date with -current
(kernel and userland) at the time of testing.  The machine below has a
kernel and libc (with my tweaks) from 4/24, and smtpd from about an
hour ago.


s...@bsd ~ $ cat /etc/mail/smtpd.conf
#       $OpenBSD: smtpd.conf,v 1.2 2009/11/03 22:32:10 gilles Exp $

# This is the smtpd server system-wide configuration file.
# See smtpd.conf(5) for more information.

listen on lo0
listen on vic0

map "aliases" { source db "/etc/mail/aliases.db" }

accept for local alias aliases deliver to mbox
accept for all relay

accept from 2001:470:8:1ee::0/64 for all relay

------

OpenBSD 4.7-current (GENERIC.MP) #553: Sat Apr 24 14:06:26 MDT 2010
    [email protected]:/usr/src/sys/arch/i386/compile/GENERIC.MP
cpu0: Intel(R) Core(TM)2 Duo CPU E4700 @ 2.60GHz ("GenuineIntel"
686-class) 2.60 GHz
cpu0: 
FPU,V86,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,SSE3,SSSE3
real mem  = 133722112 (127MB)
avail mem = 120479744 (114MB)
mainbus0 at root
bios0 at mainbus0: AT/286+ BIOS, date 09/22/09, BIOS32 rev. 0 @
0xfd780, SMBIOS rev. 2.4 @ 0xe0010 (98 entries)
bios0: vendor Phoenix Technologies LTD version "6.00" date 09/22/2009
bios0: VMware, Inc. VMware Virtual Platform
acpi0 at bios0: rev 2
acpi0: tables DSDT FACP BOOT APIC MCFG SRAT
acpi0: wakeup devices PCI0(S3) USB_(S1) P2P0(S3) S1F0(S3) S2F0(S3)
S3F0(S3) S4F0(S3) S5F0(S3) S6F0(S3) S7F0(S3) S8F0(S3) S9F0(S3)
Z00P(S3) Z00Q(S3) Z00R(S3) Z00S(S3) Z00T(S3) Z00U(S3) Z00V(S3)
Z00W(S3) Z00X(S3) Z00Y(S3) Z00Z(S3) Z010(S3) Z011(S3) Z012(S3)
Z013(S3) Z014(S3) Z015(S3) Z016(S3) Z017(S3) Z018(S3) Z019(S3)
Z01A(S3) Z01B(S3) P2P1(S3) S1F0(S3) S2F0(S3) S3F0(S3) S4F0(S3)
S5F0(S3) S6F0(S3) S7F0(S3) S8F0(S3) S9F0(S3) Z00P(S3) Z00Q(S3)
Z00R(S3) Z00S(S3) Z00T(S3) Z00U(S3) Z00V(S3) Z00W(S3) Z00X(S3)
Z00Y(S3) Z00Z(S3) Z010(S3) Z011(S3) Z012(S3) Z013(S3) Z014(S3)
Z015(S3) Z016(S3) Z017(S3) Z018(S3) Z019(S3) Z01A(S3) Z01B(S3)
P2P2(S3) S1F0(S3) S2F0(S3) S3F0(S3) S4F0(S3) S5F0(S3) S6F0(S3)
S7F0(S3) S8F0(S3) S9F0(S3) Z00P(S3) Z00Q(S3) Z00R(S3) Z00S(S3)
Z00T(S3) Z00U(S3) Z00V(S3) Z00W(S3) Z00X(S3) Z00Y(S3) Z00Z(S3)
Z010(S3) Z011(S3) Z012(S3) Z013(S3) Z014(S3) Z015(S3) Z016(S3)
Z017(S3) Z018(S3) Z019(S3) Z01A(S3) Z01B(S3) P2P3(S3) S1F0(S3)
S2F0(S3) S3F0(S3) S4F0(S3) S5F0(S3) S6F0(S3) S7F0(S3) S8F0(S3)
S9F0(S3) Z00P(S3) Z00Q(S3) Z00R(S3) Z00S(S3) Z00T(S3) Z00U(S3)
Z00V(S3) Z00W(S3) Z00X(S3) Z00Y(S3) Z00Z(S3) Z010(S3) Z011(S3)
Z012(S3) Z013(S3) Z014(S3) Z015(S3) Z016(S3) Z017(S3) Z018(S3)
Z019(S3) Z01A(S3) Z01B(S3) PE40(S3) S1F0(S3) PE50(S3) S1F0(S3)
PE60(S3) S1F0(S3) PE70(S3) S1F0(S3) PE80(S3) S1F0(S3) PE90(S3)
S1F0(S3) PEA0(S3) S1F0(S3) PEB0(S3) S1F0(S3) PEC0(S3) S1F0(S3)
PED0(S3) S1F0(S3) PEE0(S3) S1F0(S3) PE41(S3) S1F0(S3) PE42(S3)
S1F0(S3) PE43(S3) S1F0(S3) PE44(S3) S1F0(S3) PE45(S3) S1F0(S3)
PE46(S3) S1F0(S3) PE47(S3) S1F0(S3) PE51(S3) S1F0(S3) PE52(S3)
S1F0(S3) PE53(S3) S1F0(S3) PE54(S3) S1F0(S3) PE55(S3) S1F0(S3)
PE56(S3) S1F0(S3) PE57(S3) S1F0(S3) PE61(S3) S1F0(S3) PE62(S3)
S1F0(S3) PE63(S3) S1F0(S3) PE64(S3) S1F0(S3) PE65(S3) S1F0(S3)
PE66(S3) S1F0(S3) PE67(S3) S1F0(S3) PE71(S3) S1F0(S3) PE72(S3)
S1F0(S3) PE73(S3) S1F0(S3) PE74(S3) S1F0(S3) PE75(S3) S1F0(S3)
PE76(S3) S1F0(S3) PE77(S3) S1F0(S3) PE81(S3) S1F0(S3) PE82(S3)
S1F0(S3) PE83(S3) S1F0(S3) PE84(S3) S1F0(S3) PE85(S3) S1F0(S3)
PE86(S3) S1F0(S3) PE87(S3) S1F0(S3) PE91(S3) S1F0(S3) PE92(S3)
S1F0(S3) PE93(S3) S1F0(S3) PE94(S3) S1F0(S3) PE95(S3) S1F0(S3)
PE96(S3) S1F0(S3) PE97(S3) S1F0(S3) PEA1(S3) S1F0(S3) PEA2(S3)
S1F0(S3) PEA3(S3) S1F0(S3) PEA4(S3) S1F0(S3) PEA5(S3) S1F0(S3)
PEA6(S3) S1F0(S3) PEA7(S3) S1F0(S3) PEB1(S3) S1F0(S3) PEB2(S3)
S1F0(S3) PEB3(S3) S1F0(S3) PEB4(S3) S1F0(S3) PEB5(S3) S1F0(S3)
PEB6(S3) S1F0(S3) PEB7(S3) S1F0(S3) SLPB(S4)
acpitimer0 at acpi0: 3579545 Hz, 24 bits
acpimadt0 at acpi0 addr 0xfee00000: PC-AT compat
cpu0 at mainbus0: apid 0 (boot processor)
cpu0: apic clock running at 65MHz
cpu1 at mainbus0: apid 1 (application processor)
cpu1: Intel(R) Core(TM)2 Duo CPU E4700 @ 2.60GHz ("GenuineIntel"
686-class) 2.60 GHz
cpu1: 
FPU,V86,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,SSE3,SSSE3
ioapic0 at mainbus0: apid 2 pa 0xfec00000, version 11, 24 pins
acpiprt0 at acpi0: bus 0 (PCI0)
acpicpu0 at acpi0
acpicpu1 at acpi0
acpibat0 at acpi0: BAT1 not present
acpibat1 at acpi0: BAT2 not present
acpiac0 at acpi0: AC unit online
acpibtn0 at acpi0: SLPB
bios0: ROM list: 0xc0000/0x8000 0xc8000/0x1e00! 0xca000/0x1000
0xdc000/0x4000! 0xe0000/0x4000!
pci0 at mainbus0 bus 0: configuration mode 1 (bios)
pchb0 at pci0 dev 0 function 0 "Intel 82443BX AGP" rev 0x01
ppb0 at pci0 dev 1 function 0 "Intel 82443BX AGP" rev 0x01
pci1 at ppb0 bus 1
piixpcib0 at pci0 dev 7 function 0 "Intel 82371AB PIIX4 ISA" rev 0x08
pciide0 at pci0 dev 7 function 1 "Intel 82371AB IDE" rev 0x01: DMA,
channel 0 configured to compatibility, channel 1 configured to
compatibility
pciide0: channel 0 ignored (disabled)
atapiscsi0 at pciide0 channel 1 drive 0
scsibus0 at atapiscsi0: 2 targets
cd0 at scsibus0 targ 0 lun 0: <NECVMWar, VMware IDE CDR10, 1.00> ATAPI
5/cdrom removable
cd0(pciide0:1:0): using PIO mode 4, Ultra-DMA mode 2
piixpm0 at pci0 dev 7 function 3 "Intel 82371AB Power" rev 0x08: SMBus disabled
"VMware Virtual Machine Communication Interface" rev 0x10 at pci0 dev
7 function 7 not configured
vga1 at pci0 dev 15 function 0 "VMware Virtual SVGA II" rev 0x00
wsdisplay0 at vga1 mux 1: console (80x25, vt100 emulation)
wsdisplay0: screen 1-5 added (80x25, vt100 emulation)
mpi0 at pci0 dev 16 function 0 "Symbios Logic 53c1030" rev 0x01: apic
2 int 17 (irq 11)
scsibus1 at mpi0: 16 targets, initiator 7
sd0 at scsibus1 targ 0 lun 0: <VMware, Virtual disk, 1.0> SCSI2 0/direct fixed
sd0: 51200MB, 512 bytes/sec, 104857600 sec total
sd1 at scsibus1 targ 1 lun 0: <VMware, Virtual disk, 1.0> SCSI2 0/direct fixed
sd1: 102400MB, 512 bytes/sec, 209715200 sec total
sd2 at scsibus1 targ 2 lun 0: <VMware, Virtual disk, 1.0> SCSI2 0/direct fixed
sd2: 102400MB, 512 bytes/sec, 209715200 sec total
mpi0: target 0 Sync at 160MHz width 16bit offset 127 QAS 1 DT 1 IU 1
mpi0: target 1 Sync at 160MHz width 16bit offset 127 QAS 1 DT 1 IU 1
mpi0: target 2 Sync at 160MHz width 16bit offset 127 QAS 1 DT 1 IU 1
ppb1 at pci0 dev 17 function 0 "VMware Virtual PCI-PCI" rev 0x02
pci2 at ppb1 bus 2
vic0 at pci2 dev 0 function 0 "AMD 79c970 PCnet-PCI" rev 0x10: apic 2
int 18 (irq 10), address 00:0c:29:18:19:84
ppb2 at pci0 dev 21 function 0 "VMware Virtual PCIE-PCIE" rev 0x01
pci3 at ppb2 bus 3
ppb3 at pci0 dev 21 function 1 "VMware Virtual PCIE-PCIE" rev 0x01
pci4 at ppb3 bus 4
ppb4 at pci0 dev 21 function 2 "VMware Virtual PCIE-PCIE" rev 0x01
pci5 at ppb4 bus 5
ppb5 at pci0 dev 21 function 3 "VMware Virtual PCIE-PCIE" rev 0x01
pci6 at ppb5 bus 6
ppb6 at pci0 dev 21 function 4 "VMware Virtual PCIE-PCIE" rev 0x01
pci7 at ppb6 bus 7
ppb7 at pci0 dev 21 function 5 "VMware Virtual PCIE-PCIE" rev 0x01
pci8 at ppb7 bus 8
ppb8 at pci0 dev 21 function 6 "VMware Virtual PCIE-PCIE" rev 0x01
pci9 at ppb8 bus 9
ppb9 at pci0 dev 21 function 7 "VMware Virtual PCIE-PCIE" rev 0x01
pci10 at ppb9 bus 10
ppb10 at pci0 dev 22 function 0 "VMware Virtual PCIE-PCIE" rev 0x01
pci11 at ppb10 bus 11
ppb11 at pci0 dev 22 function 1 "VMware Virtual PCIE-PCIE" rev 0x01
pci12 at ppb11 bus 12
ppb12 at pci0 dev 22 function 2 "VMware Virtual PCIE-PCIE" rev 0x01
pci13 at ppb12 bus 13
ppb13 at pci0 dev 22 function 3 "VMware Virtual PCIE-PCIE" rev 0x01
pci14 at ppb13 bus 14
ppb14 at pci0 dev 22 function 4 "VMware Virtual PCIE-PCIE" rev 0x01
pci15 at ppb14 bus 15
ppb15 at pci0 dev 22 function 5 "VMware Virtual PCIE-PCIE" rev 0x01
pci16 at ppb15 bus 16
ppb16 at pci0 dev 22 function 6 "VMware Virtual PCIE-PCIE" rev 0x01
pci17 at ppb16 bus 17
ppb17 at pci0 dev 22 function 7 "VMware Virtual PCIE-PCIE" rev 0x01
pci18 at ppb17 bus 18
ppb18 at pci0 dev 23 function 0 "VMware Virtual PCIE-PCIE" rev 0x01
pci19 at ppb18 bus 19
ppb19 at pci0 dev 23 function 1 "VMware Virtual PCIE-PCIE" rev 0x01
pci20 at ppb19 bus 20
ppb20 at pci0 dev 23 function 2 "VMware Virtual PCIE-PCIE" rev 0x01
pci21 at ppb20 bus 21
ppb21 at pci0 dev 23 function 3 "VMware Virtual PCIE-PCIE" rev 0x01
pci22 at ppb21 bus 22
ppb22 at pci0 dev 23 function 4 "VMware Virtual PCIE-PCIE" rev 0x01
pci23 at ppb22 bus 23
ppb23 at pci0 dev 23 function 5 "VMware Virtual PCIE-PCIE" rev 0x01
pci24 at ppb23 bus 24
ppb24 at pci0 dev 23 function 6 "VMware Virtual PCIE-PCIE" rev 0x01
pci25 at ppb24 bus 25
ppb25 at pci0 dev 23 function 7 "VMware Virtual PCIE-PCIE" rev 0x01
pci26 at ppb25 bus 26
ppb26 at pci0 dev 24 function 0 "VMware Virtual PCIE-PCIE" rev 0x01
pci27 at ppb26 bus 27
ppb27 at pci0 dev 24 function 1 "VMware Virtual PCIE-PCIE" rev 0x01
pci28 at ppb27 bus 28
ppb28 at pci0 dev 24 function 2 "VMware Virtual PCIE-PCIE" rev 0x01
pci29 at ppb28 bus 29
ppb29 at pci0 dev 24 function 3 "VMware Virtual PCIE-PCIE" rev 0x01
pci30 at ppb29 bus 30
ppb30 at pci0 dev 24 function 4 "VMware Virtual PCIE-PCIE" rev 0x01
pci31 at ppb30 bus 31
ppb31 at pci0 dev 24 function 5 "VMware Virtual PCIE-PCIE" rev 0x01
pci32 at ppb31 bus 32
ppb32 at pci0 dev 24 function 6 "VMware Virtual PCIE-PCIE" rev 0x01
pci33 at ppb32 bus 33
ppb33 at pci0 dev 24 function 7 "VMware Virtual PCIE-PCIE" rev 0x01
pci34 at ppb33 bus 34
isa0 at piixpcib0
isadma0 at isa0
com0 at isa0 port 0x3f8/8 irq 4: ns16550a, 16 byte fifo
com1 at isa0 port 0x2f8/8 irq 3: ns16550a, 16 byte fifo
pckbc0 at isa0 port 0x60/5
pckbd0 at pckbc0 (kbd slot)
pckbc0: using irq 1 for kbd slot
wskbd0 at pckbd0: console keyboard, using wsdisplay0
pmsi0 at pckbc0 (aux slot)
pckbc0: using irq 12 for aux slot
wsmouse0 at pmsi0 mux 0
pcppi0 at isa0 port 0x61
midi0 at pcppi0: <PC speaker>
spkr0 at pcppi0
lpt0 at isa0 port 0x378/4 irq 7
npx0 at isa0 port 0xf0/16: reported by CPUID; using exception 16
fdc0 at isa0 port 0x3f0/6 irq 6 drq 2
fd0 at fdc0 drive 0: 1.44MB 80 cyl, 2 head, 18 sec
mtrr: Pentium Pro MTRR support
vscsi0 at root
scsibus2 at vscsi0: 256 targets
softraid0 at root
root on sd0a swap on sd0b dump on sd0b

------------------

Finally, here's the diff of what I pulled from NetBSD and applied to libc:


Index: inet_net_ntop.c
===================================================================
RCS file: /cvs/src/lib/libc/net/inet_net_ntop.c,v
retrieving revision 1.6
diff -u -p inet_net_ntop.c
--- inet_net_ntop.c     6 Aug 2005 20:30:03 -0000       1.6
+++ inet_net_ntop.c     30 Apr 2010 05:52:37 -0000
@@ -27,7 +27,8 @@
 #include <string.h>
 #include <stdlib.h>

-static char *inet_net_ntop_ipv4(const u_char *, int, char *, size_t);
+static char *  inet_net_ntop_ipv4(const u_char *, int, char *, size_t);
+static char *  inet_net_ntop_ipv6(const u_char *, int, char *, size_t);

 /*
  * char *
@@ -45,6 +46,8 @@ inet_net_ntop(int af, const void *src, int bits, char
        switch (af) {
        case AF_INET:
                return (inet_net_ntop_ipv4(src, bits, dst, size));
+       case AF_INET6:
+               return (inet_net_ntop_ipv6(src, bits, dst, size));
        default:
                errno = EAFNOSUPPORT;
                return (NULL);
@@ -130,6 +133,152 @@ inet_net_ntop_ipv4(const u_char *src, int bits, char *
        return (odst);

  emsgsize:
+       errno = EMSGSIZE;
+       return (NULL);
+}
+
+/*
+ * static char *
+ * inet_net_ntop_ipv6(src, bits, fakebits, dst, size)
+ *     convert IPv6 network number from network to presentation format.
+ *     generates CIDR style result always. Picks the shortest representation
+ *     unless the IP is really IPv4.
+ *     always prints specified number of bits (bits).
+ * return:
+ *     pointer to dst, or NULL if an error occurred (check errno).
+ * note:
+ *     network byte order assumed.  this means 192.5.5.240/28 has
+ *     0x11110000 in its fourth octet.
+ * author:
+ *     Vadim Kogan (UCB), June 2001
+ *  Original version (IPv4) by Paul Vixie (ISC), July 1996
+ */
+
+static char *
+inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size)
+{
+       size_t  bytes;
+       u_int   m;
+       int     b;
+       int     p;
+       int     zero_s, zero_l, tmp_zero_s, tmp_zero_l;
+       int     i;
+       int     is_ipv4 = 0;
+       u_char inbuf[16];
+       char 
outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
+       char    *cp;
+       int     words;
+       u_char  *s;
+       char    *ep;
+       int     advance;
+
+       if (bits < 0 || bits > 128) {
+               errno = EINVAL;
+               return (NULL);
+       }
+
+       cp = outbuf;
+       ep = outbuf + sizeof(outbuf);
+
+       if (bits == 0) {
+               *cp++ = ':';
+               *cp++ = ':';
+               *cp = '\0';
+       } else {
+               /* Copy src to private buffer.  Zero host part. */      
+               bytes = (bits + 7) / 8;
+               memcpy(inbuf, src, bytes);
+               memset(inbuf + bytes, 0, 16 - bytes);
+               b = bits % 8;
+               if (b != 0) {
+                       m = ~0 << (8 - b);
+                       inbuf[bytes-1] &= m;
+               }
+
+               s = inbuf;
+
+               /* how many words need to be displayed in output */
+               words = (bits + 15) / 16;
+               if (words == 1)
+                       words = 2;
+               
+               /* Find the longest substring of zero's */
+               zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0;
+               for (i = 0; i < (words * 2); i += 2) {
+                       if ((s[i] | s[i+1]) == 0) {
+                               if (tmp_zero_l == 0)
+                                       tmp_zero_s = i / 2;
+                               tmp_zero_l++;
+                       } else {
+                               if (tmp_zero_l && zero_l < tmp_zero_l) {
+                                       zero_s = tmp_zero_s;
+                                       zero_l = tmp_zero_l;
+                                       tmp_zero_l = 0;
+                               }
+                       }
+               }
+
+               if (tmp_zero_l && zero_l < tmp_zero_l) {
+                       zero_s = tmp_zero_s;
+                       zero_l = tmp_zero_l;
+               }
+
+               if (zero_l != words && zero_s == 0 && ((zero_l == 6) ||
+                   ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) ||
+                   ((zero_l == 7 && s[14] != 0 && s[15] != 1)))))
+                       is_ipv4 = 1;
+
+               /* Format whole words. */
+               for (p = 0; p < words; p++) {
+                       if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l) {
+                               /* Time to skip some zeros */
+                               if (p == zero_s)
+                                       *cp++ = ':';
+                               if (p == words - 1)
+                                       *cp++ = ':';
+                               s++;
+                               s++;
+                               continue;
+                       }
+
+                       if (is_ipv4 && p > 5) {
+                               *cp++ = (p == 6) ? ':' : '.';
+                               advance = snprintf(cp, (size_t)(ep - cp),
+                                   "%u", *s++);
+                               if (advance <= 0 || advance >= ep - cp)
+                                       goto emsgsize;
+                               cp += advance;
+                               /* we can potentially drop the last octet */
+                               if (p != 7 || bits > 120) {
+                                       *cp++ = '.';
+                                       advance = snprintf(cp,
+                                           (size_t)(ep - cp), "%u", *s++);
+                                       if (advance <= 0 || advance >= ep - cp)
+                                               goto emsgsize;
+                                       cp += advance;
+                               }
+                       } else {
+                               if (cp != outbuf)
+                                       *cp++ = ':';
+                               advance = snprintf(cp, (size_t)(ep - cp), "%x",
+                                   *s * 256 + s[1]);
+                               if (advance <= 0 || advance >= ep - cp)
+                                       goto emsgsize;
+                               cp += advance;
+                               s += 2;
+                       }
+               }
+       }
+       /* Format CIDR /width. */
+       /* LINTED */
+       snprintf(cp, ep - cp, "/%u", bits);
+       if (strlen(outbuf) + 1 > size)
+               goto emsgsize;
+       strlcpy(dst, outbuf, size);
+       
+       return (dst);
+
+emsgsize:
        errno = EMSGSIZE;
        return (NULL);
 }
Index: inet_net_pton.c
===================================================================
RCS file: /cvs/src/lib/libc/net/inet_net_pton.c,v
retrieving revision 1.6
diff -u -p inet_net_pton.c
--- inet_net_pton.c     1 Sep 2008 09:40:43 -0000       1.6
+++ inet_net_pton.c     30 Apr 2010 05:52:37 -0000
@@ -21,6 +21,7 @@
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+#include <arpa/nameser.h>

 #include <assert.h>
 #include <ctype.h>
@@ -30,6 +31,9 @@
 #include <stdlib.h>

 static int     inet_net_pton_ipv4(const char *, u_char *, size_t);
+static int     inet_net_pton_ipv6(const char *, u_char *, size_t);
+static int     getbits(const char *, int *);
+static int     getv4(const char *, u_char *, int *);

 /*
  * static int
@@ -50,6 +54,8 @@ inet_net_pton(int af, const char *src, void *dst, size
        switch (af) {
        case AF_INET:
                return (inet_net_pton_ipv4(src, dst, size));
+       case AF_INET6:
+               return (inet_net_pton_ipv6(src, dst, size));
        default:
                errno = EAFNOSUPPORT;
                return (-1);
@@ -179,6 +185,201 @@ inet_net_pton_ipv4(const char *src, u_char *dst, size_
                        goto emsgsize;
                *dst++ = '\0';
        }
+       return (bits);
+
+ enoent:
+       errno = ENOENT;
+       return (-1);
+
+ emsgsize:
+       errno = EMSGSIZE;
+       return (-1);
+}
+
+static int
+getbits(const char *src, int *bitsp)
+{
+       static const char digits[] = "0123456789";
+       int n;
+       int val;
+       char ch;
+
+       val = 0;
+       n = 0;
+       while ((ch = *src++) != '\0') {
+               const char *pch;
+
+               pch = strchr(digits, ch);
+               if (pch != NULL) {
+                       if (n++ != 0 && val == 0)       /* no leading zeros */
+                               return (0);
+                       val *= 10;
+                       val += (pch - digits);
+                       if (val > 128)                  /* range */
+                               return (0);
+                       continue;
+               }
+               return (0);
+       }
+       if (n == 0)
+               return (0);
+       *bitsp = val;
+       return (1);
+}
+
+static int
+getv4(const char *src, u_char *dst, int *bitsp)
+{
+       static const char digits[] = "0123456789";
+       u_char *odst = dst;
+       int n;
+       u_int val;
+       char ch;
+
+       val = 0;
+       n = 0;
+       while ((ch = *src++) != '\0') {
+               const char *pch;
+
+               pch = strchr(digits, ch);
+               if (pch != NULL) {
+                       if (n++ != 0 && val == 0)       /* no leading zeros */
+                               return (0);
+                       val *= 10;
+                       val += (pch - digits);
+                       if (val > 255)                  /* range */
+                               return (0);
+                       continue;
+               }
+               if (ch == '.' || ch == '/') {
+                       if (dst - odst > 3)             /* too many octets? */
+                               return (0);
+                       *dst++ = val;
+                       if (ch == '/')
+                               return (getbits(src, bitsp));
+                       val = 0;
+                       n = 0;
+                       continue;
+               }
+               return (0);
+       }
+       if (n == 0)
+               return (0);
+       if (dst - odst > 3)             /* too many octets? */
+               return (0);
+       *dst++ = val;
+       return (1);
+}
+
+static int
+inet_net_pton_ipv6(const char *src, u_char *dst, size_t size)
+{
+       static const char xdigits_l[] = "0123456789abcdef",
+                         xdigits_u[] = "0123456789ABCDEF";
+       u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
+       const char *xdigits, *curtok;
+       int ch, saw_xdigit;
+       u_int val;
+       int digits;
+       int bits;
+       size_t bytes;
+       int words;
+       int ipv4;
+
+       memset((tp = tmp), '\0', IN6ADDRSZ);
+       endp = tp + IN6ADDRSZ;
+       colonp = NULL;
+       /* Leading :: requires some special handling. */
+       if (*src == ':')
+               if (*++src != ':')
+                       goto enoent;
+       curtok = src;
+       saw_xdigit = 0;
+       val = 0;
+       digits = 0;
+       bits = -1;
+       ipv4 = 0;
+       while ((ch = *src++) != '\0') {
+               const char *pch;
+
+               if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+                       pch = strchr((xdigits = xdigits_u), ch);
+               if (pch != NULL) {
+                       val <<= 4;
+                       val |= (pch - xdigits);
+                       if (++digits > 4)
+                               goto enoent;
+                       saw_xdigit = 1;
+                       continue;
+               }
+               if (ch == ':') {
+                       curtok = src;
+                       if (!saw_xdigit) {
+                               if (colonp)
+                                       goto enoent;
+                               colonp = tp;
+                               continue;
+                       } else if (*src == '\0')
+                               goto enoent;
+                       if (tp + INT16SZ > endp)
+                               return (0);
+                       *tp++ = (u_char) (val >> 8) & 0xff;
+                       *tp++ = (u_char) val & 0xff;
+                       saw_xdigit = 0;
+                       digits = 0;
+                       val = 0;
+                       continue;
+               }
+               if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
+                    getv4(curtok, tp, &bits) > 0) {
+                       tp += INADDRSZ;
+                       saw_xdigit = 0;
+                       ipv4 = 1;
+                       break;  /* '\0' was seen by inet_pton4(). */
+               }
+               if (ch == '/' && getbits(src, &bits) > 0)
+                       break;
+               goto enoent;
+       }
+       if (saw_xdigit) {
+               if (tp + INT16SZ > endp)
+                       goto enoent;
+               *tp++ = (u_char) (val >> 8) & 0xff;
+               *tp++ = (u_char) val & 0xff;
+       }
+       if (bits == -1)
+               bits = 128;
+
+       words = (bits + 15) / 16;
+       if (words < 2)
+               words = 2;
+       if (ipv4)
+               words = 8;
+       endp =  tmp + 2 * words;
+
+       if (colonp != NULL) {
+               /*
+                * Since some memmove()'s erroneously fail to handle
+                * overlapping regions, we'll do the shift by hand.
+                */
+               const int n = tp - colonp;
+               int i;
+
+               if (tp == endp)
+                       goto enoent;
+               for (i = 1; i <= n; i++) {
+                       endp[- i] = colonp[n - i];
+                       colonp[n - i] = 0;
+               }
+               tp = endp;
+       }
+       if (tp != endp)
+               goto enoent;
+
+       bytes = (bits + 7) / 8;
+       if (bytes > size)
+               goto emsgsize;
+       memcpy(dst, tmp, bytes);
        return (bits);

  enoent:

Reply via email to