Hah. No worries; I'm just glad that I wasn't too terribly off-base. :-) I can be available for testing if needed.
Thanks! --seth On Fri, Apr 30, 2010 at 2:31 AM, Gilles Chehade <[email protected]> wrote: > 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,CFLUS H,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,CFLUS H,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
