Hi Seth,
It is a known issue, I actually had pulled the code for inet_net_pton()
from NetBSD many months ago, when I first realized inet6 masks were not
working in smtpd, but then I got sucked into other stuff and forgot it.
I'll review the diff again ... :-)
Thanks,
Gilles
On Fri, Apr 30, 2010 at 02:13:11AM -0400, Seth Wright wrote:
> 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:
>
--
Gilles Chehade
freelance developer/sysadmin/consultant
http://www.poolp.org