From: | Bruce Momjian <maillist(at)candle(dot)pha(dot)pa(dot)us> |
---|---|
To: | tih(at)nhh(dot)no (Tom Ivar Helbekkmo) |
Cc: | hackers(at)postgreSQL(dot)org (PostgreSQL-development), vixie(at)vix(dot)com |
Subject: | Re: CIDR/IP types. Was: [GENERAL] big numbers |
Date: | 1998-09-08 15:07:08 |
Message-ID: | 199809081507.LAA10039@candle.pha.pa.us |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Thread: | |
Lists: | pgsql-general pgsql-hackers |
Good. Keep going and let me know when you want it added. We need to
fix the other problems first before merging your stuff in, so we have
some time. I assume you are merging Paul's code with your own, to make
a "best of both worlds" group of types.
> Bruce Momjian wrote:
>
> > When do you think you can you look over both versions, and send me
> > one good version to work with?
>
> I've got something working right now, by taking what I was using, and
> changing it to work the way Paul's code does, with some enhancements:
> My code is ready for storing both IPV4 and IPV6 at the same time with
> variable length storage in the data base, and it's got Aleksei's index
> integration in place. The type name is still "ipaddr" -- but that's
> easy to change, of course.
>
> > Even if you just say, "Paul's is better, throw out ip_and_mac", that
> > is all we need.
>
> I am definitely *not* going to say "I can do this better than Vixie".
>
> The way I feel about this right now is that Paul's code is better than
> what I originally submitted, and better than Aleksei's improvements on
> that code. However, what I currently run has certain improvements
> over all of those versions, and I kind of like the way it's going...
>
> I'll append it below. Take a look, and let me know what you think.
>
> Oh, and a correction: Paul Vixie wrote:
>
> > the ip_and_mac type is host-only but has an unfortunate bridging
> > between layer 3 and layer 2.
>
> No, it was (and is) two different types, just packaged in the same
> directory because I thought they conceptually belonged together.
>
> Anyway, I'm appending a shar of what I've got right now. It's only
> minimally tested so far, and I'm *not* a professional programmer.
> I'm basically just having a lot of fun with this, while it is at the
> same time useful for me in my work, and if what I write can be of use
> to others, that's great! :-)
>
> -tih
> --
> Popularity is the hallmark of mediocrity. --Niles Crane, "Frasier"
>
> # This is a shell archive. Save it in a file, remove anything before
> # this line, and then unpack it by entering "sh file". Note, it may
> # create directories; files and directories will be owned by you and
> # have default permissions.
> #
> # This archive contains:
> #
> # Makefile
> # README
> # inet_net_ntop.c
> # inet_net_pton.c
> # ip.c
> # ip.sql.in
> # mac.c
> # mac.h
> # mac.sql.in
> # test.sql
> #
> echo x - Makefile
> sed 's/^X//' >Makefile << 'END-of-Makefile'
> X#
> X# PostgreSQL types for IP and MAC addresses
> X#
> X# $Id: Makefile,v 1.4 1998/09/08 12:23:30 tih Exp $
> X
> XPGINST=/usr/local/pgsql
> XTARGET=/u/tih/databases
> X
> Xall: ip.so mac.so ip.sql mac.sql
> X
> Xip.so: ip.o inet_net_ntop.o inet_net_pton.o
> X ld -Bshareable -o ip.so ip.o inet_net_ntop.o inet_net_pton.o
> X
> Xip.o: ip.c
> X cc -g -O -fPIC -I${PGINST}/include -c ip.c
> X
> Xinet_net_ntop.o: inet_net_ntop.c
> X cc -g -O -fPIC -c inet_net_ntop.c
> X
> Xinet_net_pton.o: inet_net_pton.c
> X cc -g -O -fPIC -c inet_net_pton.c
> X
> Xmac.so: mac.o
> X ld -Bshareable -o mac.so mac.o
> X
> Xmac.o: mac.c mac.h
> X cc -g -O -fPIC -I${PGINST}/include -c mac.c
> X
> Xip.sql: ip.sql.in
> X cat ip.sql.in | sed s(at)TARGET@${TARGET}/modules@ > ip.sql
> X
> Xmac.sql: mac.sql.in
> X cat mac.sql.in | sed s(at)TARGET@${TARGET}/modules@ > mac.sql
> X
> Xinstall: ip.so mac.so
> X install -c ip.sql ip.so mac.sql mac.so ${TARGET}/modules
> X
> Xclean:
> X rm -f *.o *.so ip.sql mac.sql
> X
> XFILES=Makefile README inet_net_ntop.c inet_net_pton.c \
> X ip.c ip.sql.in mac.c mac.h mac.sql.in test.sql
> X
> Xip+mac.shar: ${FILES}
> X shar ${FILES} > ip+mac.shar
> X
> X#
> X# eof
> X#
> END-of-Makefile
> echo x - README
> sed 's/^X//' >README << 'END-of-README'
> XPostgreSQL type extensions for IP and MAC addresses.
> X---------------------------------------------------
> X
> X$Id: README,v 1.2 1998/09/08 12:10:22 tih Exp $
> X
> XI needed to record IP and MAC level ethernet addresses in a data
> Xbase, and I really didn't want to store them as plain strings, with
> Xno enforced error checking, so I put together the accompanying code
> Xas my first experiment with adding a data type to PostgreSQL. I
> Xthen thought that this might be useful to others, both directly and
> Xas a very simple example of how to do this sort of thing, so I
> Xsubmitted it to the PostgreSQL project for inclusion in the contrib
> Xdirectory. Since then, that directory has been modified to contain
> XAleksei Roudnev's implementation, which is based on mine.
> X
> XFor those who have seen my previous contribution of these types, note
> Xthat much has changed: I've modified the IP address type to work the
> Xway Paul Vixie did with his CIDR type. In fact, I've pretty much just
> Xstolen his solution, modifying it into my framework in such a way as
> Xto facilitate the addition of IPV6 handling code in the future. I've
> Xpretty much ignored Aleksei's C code, but I've added his SQL code to
> Xenter the necessary operators into the various system tables needed to
> Xmake the types indexable.
> X
> XIP addresses are implemented as a struct of fixed in-memory length,
> Xbut variable on-disk storage size. For IPV4, it contains the address
> Xfamily (AF_INET), the CIDR prefix length and four byte address. For
> XIPV6, the address family will be different, and the address longer.
> X
> XThe external representation of an IP address generally looks like
> X'158.37.96.15/32'. This address happens to be part of a subnet where
> XI work; '158.37.96.0/24', which itself is a part of the larger subnet
> Xallocated to our site, which is '158.37.96.0/21', which again, if you
> Xgo by the old book, is part of the class "B" net '158.37.0.0/16'.
> X
> XInput and output functions are supplied, along with the "normal" <,
> X<=, =, >=, > and <> operators, which all do what you expect. In
> Xaddition, there are operators to check for networks or addresses being
> Xsubnets of or addresses contained within other networks. << tests
> Xwhether the left operand is contained within the right, <<= includes
> Xequality, >> and >>= do the same things the opposite way.
> X
> XThe input and output functions use routines from Paul Vixie's BIND,
> Xand I've snarfed the source files inet_net_ntop.c and inet_net_pton.c
> Xdirectly from a recent distribution of that code. They are included
> Xhere to avoid the need to fetch and install the BIND libraries to be
> Xable to use this code. IANAL, but it looks from the copyright
> Xmessages in the files as if this should be acceptable. Read the
> Xdocumentation in inet_net_pton.c to see the legal input formats.
> X
> XMAC level ethernet addresses are implemented as a 6 byte struct that
> Xcontains the address as unsigned chars. Several input forms are
> Xaccepted; the following are all the same address: '08002b:010203',
> X'08002b-010203', '0800.2b01.0203', '08-00-2b-01-02-03' and
> X'08:00:2b:01:02:03'. Upper and lower case is accepted for the digits
> X'a' through 'f'. Output is always in the latter of the given forms.
> X
> XAs with IP addresses, input and output functions are supplied as well
> Xas the "normal" operators, which do what you expect. As an extra
> Xfeature, a function macaddr_manuf() is defined, which returns the name
> Xof the manufacturer as a string. This is currently held in a
> Xhard-coded struct internal to the C module -- it might be smarter to
> Xput this information into an actual data base table, and look up the
> Xmanufacturer there.
> X
> XMany thanks to Aleksei Roudnev and Paul Vixie for their fine work!
> X
> XI don't know what changes are needed to the Makefile for other systems
> Xthan the one I'm running (NetBSD 1.3), but anyway: to install on a BSD
> Xsystem: fix the path names in the Makefile if you need to, then make,
> Xmake install, slurp the SQL files into psql or whatever, and you're
> Xoff. Enjoy!
> X
> XBergen, Norway, 1998-08-09, Tom Ivar Helbekkmo (tih(at)nhh(dot)no).
> END-of-README
> echo x - inet_net_ntop.c
> sed 's/^X//' >inet_net_ntop.c << 'END-of-inet_net_ntop.c'
> X/*
> X * Copyright (c) 1996 by Internet Software Consortium.
> X *
> X * Permission to use, copy, modify, and distribute this software for any
> X * purpose with or without fee is hereby granted, provided that the above
> X * copyright notice and this permission notice appear in all copies.
> X *
> X * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
> X * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
> X * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
> X * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
> X * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
> X * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
> X * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
> X * SOFTWARE.
> X */
> X
> X#if defined(LIBC_SCCS) && !defined(lint)
> Xstatic const char rcsid[] = "$Id: inet_net_ntop.c,v 8.2 1996/08/08 06:54:44 vixie Exp $";
> X#endif
> X
> X#include <sys/types.h>
> X#include <sys/socket.h>
> X#include <netinet/in.h>
> X#include <arpa/inet.h>
> X
> X#include <errno.h>
> X#include <stdio.h>
> X#include <string.h>
> X#include <stdlib.h>
> X
> X#ifdef SPRINTF_CHAR
> X# define SPRINTF(x) strlen(sprintf/**/x)
> X#else
> X# define SPRINTF(x) ((size_t)sprintf x)
> X#endif
> X
> Xstatic char * inet_net_ntop_ipv4 __P((const u_char *src, int bits,
> X char *dst, size_t size));
> X
> X/*
> X * char *
> X * inet_net_ntop(af, src, bits, dst, size)
> X * convert network number from network to presentation format.
> X * generates CIDR style result always.
> X * return:
> X * pointer to dst, or NULL if an error occurred (check errno).
> X * author:
> X * Paul Vixie (ISC), July 1996
> X */
> Xchar *
> Xinet_net_ntop(af, src, bits, dst, size)
> X int af;
> X const void *src;
> X int bits;
> X char *dst;
> X size_t size;
> X{
> X switch (af) {
> X case AF_INET:
> X return (inet_net_ntop_ipv4(src, bits, dst, size));
> X default:
> X errno = EAFNOSUPPORT;
> X return (NULL);
> X }
> X}
> X
> X/*
> X * static char *
> X * inet_net_ntop_ipv4(src, bits, dst, size)
> X * convert IPv4 network number from network to presentation format.
> X * generates CIDR style result always.
> X * return:
> X * pointer to dst, or NULL if an error occurred (check errno).
> X * note:
> X * network byte order assumed. this means 192.5.5.240/28 has
> X * 0x11110000 in its fourth octet.
> X * author:
> X * Paul Vixie (ISC), July 1996
> X */
> Xstatic char *
> Xinet_net_ntop_ipv4(src, bits, dst, size)
> X const u_char *src;
> X int bits;
> X char *dst;
> X size_t size;
> X{
> X char *odst = dst;
> X char *t;
> X u_int m;
> X int b;
> X
> X if (bits < 0 || bits > 32) {
> X errno = EINVAL;
> X return (NULL);
> X }
> X if (bits == 0) {
> X if (size < sizeof "0")
> X goto emsgsize;
> X *dst++ = '0';
> X *dst = '\0';
> X }
> X
> X /* Format whole octets. */
> X for (b = bits / 8; b > 0; b--) {
> X if (size < sizeof "255.")
> X goto emsgsize;
> X t = dst;
> X dst += SPRINTF((dst, "%u", *src++));
> X if (b > 1) {
> X *dst++ = '.';
> X *dst = '\0';
> X }
> X size -= (size_t)(dst - t);
> X }
> X
> X /* Format partial octet. */
> X b = bits % 8;
> X if (b > 0) {
> X if (size < sizeof ".255")
> X goto emsgsize;
> X t = dst;
> X if (dst != odst)
> X *dst++ = '.';
> X m = ((1 << b) - 1) << (8 - b);
> X dst += SPRINTF((dst, "%u", *src & m));
> X size -= (size_t)(dst - t);
> X }
> X
> X /* Format CIDR /width. */
> X if (size < sizeof "/32")
> X goto emsgsize;
> X dst += SPRINTF((dst, "/%u", bits));
> X return (odst);
> X
> X emsgsize:
> X errno = EMSGSIZE;
> X return (NULL);
> X}
> END-of-inet_net_ntop.c
> echo x - inet_net_pton.c
> sed 's/^X//' >inet_net_pton.c << 'END-of-inet_net_pton.c'
> X/*
> X * Copyright (c) 1996 by Internet Software Consortium.
> X *
> X * Permission to use, copy, modify, and distribute this software for any
> X * purpose with or without fee is hereby granted, provided that the above
> X * copyright notice and this permission notice appear in all copies.
> X *
> X * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
> X * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
> X * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
> X * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
> X * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
> X * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
> X * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
> X * SOFTWARE.
> X */
> X
> X#if defined(LIBC_SCCS) && !defined(lint)
> Xstatic const char rcsid[] = "$Id: inet_net_pton.c,v 8.3 1996/11/11 06:36:52 vixie Exp $";
> X#endif
> X
> X#include <sys/types.h>
> X#include <sys/socket.h>
> X#include <netinet/in.h>
> X#include <arpa/inet.h>
> X
> X#include <assert.h>
> X#include <ctype.h>
> X#include <errno.h>
> X#include <stdio.h>
> X#include <string.h>
> X#include <stdlib.h>
> X
> X#ifdef SPRINTF_CHAR
> X# define SPRINTF(x) strlen(sprintf/**/x)
> X#else
> X# define SPRINTF(x) ((size_t)sprintf x)
> X#endif
> X
> Xstatic int inet_net_pton_ipv4 __P((const char *src, u_char *dst,
> X size_t size));
> X
> X/*
> X * static int
> X * inet_net_pton(af, src, dst, size)
> X * convert network number from presentation to network format.
> X * accepts hex octets, hex strings, decimal octets, and /CIDR.
> X * "size" is in bytes and describes "dst".
> X * return:
> X * number of bits, either imputed classfully or specified with /CIDR,
> X * or -1 if some failure occurred (check errno). ENOENT means it was
> X * not a valid network specification.
> X * author:
> X * Paul Vixie (ISC), June 1996
> X */
> Xint
> Xinet_net_pton(af, src, dst, size)
> X int af;
> X const char *src;
> X void *dst;
> X size_t size;
> X{
> X switch (af) {
> X case AF_INET:
> X return (inet_net_pton_ipv4(src, dst, size));
> X default:
> X errno = EAFNOSUPPORT;
> X return (-1);
> X }
> X}
> X
> X/*
> X * static int
> X * inet_net_pton_ipv4(src, dst, size)
> X * convert IPv4 network number from presentation to network format.
> X * accepts hex octets, hex strings, decimal octets, and /CIDR.
> X * "size" is in bytes and describes "dst".
> X * return:
> X * number of bits, either imputed classfully or specified with /CIDR,
> X * or -1 if some failure occurred (check errno). ENOENT means it was
> X * not an IPv4 network specification.
> X * note:
> X * network byte order assumed. this means 192.5.5.240/28 has
> X * 0x11110000 in its fourth octet.
> X * author:
> X * Paul Vixie (ISC), June 1996
> X */
> Xstatic int
> Xinet_net_pton_ipv4(src, dst, size)
> X const char *src;
> X u_char *dst;
> X size_t size;
> X{
> X static const char
> X xdigits[] = "0123456789abcdef",
> X digits[] = "0123456789";
> X int n, ch, tmp, dirty, bits;
> X const u_char *odst = dst;
> X
> X ch = *src++;
> X if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
> X && isascii(src[1]) && isxdigit(src[1])) {
> X /* Hexadecimal: Eat nybble string. */
> X if (size <= 0)
> X goto emsgsize;
> X *dst = 0, dirty = 0;
> X src++; /* skip x or X. */
> X while ((ch = *src++) != '\0' &&
> X isascii(ch) && isxdigit(ch)) {
> X if (isupper(ch))
> X ch = tolower(ch);
> X n = strchr(xdigits, ch) - xdigits;
> X assert(n >= 0 && n <= 15);
> X *dst |= n;
> X if (!dirty++)
> X *dst <<= 4;
> X else if (size-- > 0)
> X *++dst = 0, dirty = 0;
> X else
> X goto emsgsize;
> X }
> X if (dirty)
> X size--;
> X } else if (isascii(ch) && isdigit(ch)) {
> X /* Decimal: eat dotted digit string. */
> X for (;;) {
> X tmp = 0;
> X do {
> X n = strchr(digits, ch) - digits;
> X assert(n >= 0 && n <= 9);
> X tmp *= 10;
> X tmp += n;
> X if (tmp > 255)
> X goto enoent;
> X } while ((ch = *src++) != '\0' &&
> X isascii(ch) && isdigit(ch));
> X if (size-- <= 0)
> X goto emsgsize;
> X *dst++ = (u_char) tmp;
> X if (ch == '\0' || ch == '/')
> X break;
> X if (ch != '.')
> X goto enoent;
> X ch = *src++;
> X if (!isascii(ch) || !isdigit(ch))
> X goto enoent;
> X }
> X } else
> X goto enoent;
> X
> X bits = -1;
> X if (ch == '/' && isascii(src[0]) && isdigit(src[0]) && dst > odst) {
> X /* CIDR width specifier. Nothing can follow it. */
> X ch = *src++; /* Skip over the /. */
> X bits = 0;
> X do {
> X n = strchr(digits, ch) - digits;
> X assert(n >= 0 && n <= 9);
> X bits *= 10;
> X bits += n;
> X } while ((ch = *src++) != '\0' &&
> X isascii(ch) && isdigit(ch));
> X if (ch != '\0')
> X goto enoent;
> X if (bits > 32)
> X goto emsgsize;
> X }
> X
> X /* Firey death and destruction unless we prefetched EOS. */
> X if (ch != '\0')
> X goto enoent;
> X
> X /* If nothing was written to the destination, we found no address. */
> X if (dst == odst)
> X goto enoent;
> X /* If no CIDR spec was given, infer width from net class. */
> X if (bits == -1) {
> X if (*odst >= 240) /* Class E */
> X bits = 32;
> X else if (*odst >= 224) /* Class D */
> X bits = 4;
> X else if (*odst >= 192) /* Class C */
> X bits = 24;
> X else if (*odst >= 128) /* Class B */
> X bits = 16;
> X else /* Class A */
> X bits = 8;
> X /* If imputed mask is narrower than specified octets, widen. */
> X if (bits >= 8 && bits < ((dst - odst) * 8))
> X bits = (dst - odst) * 8;
> X }
> X /* Extend network to cover the actual mask. */
> X while (bits > ((dst - odst) * 8)) {
> X if (size-- <= 0)
> X goto emsgsize;
> X *dst++ = '\0';
> X }
> X return (bits);
> X
> X enoent:
> X errno = ENOENT;
> X return (-1);
> X
> X emsgsize:
> X errno = EMSGSIZE;
> X return (-1);
> X}
> END-of-inet_net_pton.c
> echo x - ip.c
> sed 's/^X//' >ip.c << 'END-of-ip.c'
> X/*
> X * PostgreSQL type definitions for IP addresses. This
> X * is for IP V4 CIDR notation, but prepared for V6: just
> X * add the necessary bits where the comments indicate.
> X *
> X * $Id: ip.c,v 1.2 1998/09/08 12:10:36 tih Exp $
> X */
> X
> X#include <sys/types.h>
> X#include <sys/socket.h>
> X
> X#include <stdio.h>
> X#include <errno.h>
> X
> X#include <netinet/in.h>
> X#include <arpa/inet.h>
> X
> X#include <postgres.h>
> X#include <utils/palloc.h>
> X
> X/*
> X * This is the internal storage format for IP addresses:
> X */
> X
> Xtypedef struct {
> X unsigned char family;
> X unsigned char bits;
> X union {
> X u_int32_t ipv4_addr; /* network byte order */
> X /* add IPV6 address type here */
> X } addr;
> X} ipaddr_struct;
> X
> Xtypedef struct varlena ipaddr;
> X
> X/*
> X * Access macros. Add IPV6 support.
> X */
> X
> X#define ip_addrsize(ipaddrptr) \
> X (((ipaddr_struct *)VARDATA(ipaddrptr))->family == AF_INET ? 4 : -1)
> X
> X#define ip_family(ipaddrptr) \
> X (((ipaddr_struct *)VARDATA(ipaddrptr))->family)
> X
> X#define ip_bits(ipaddrptr) \
> X (((ipaddr_struct *)VARDATA(ipaddrptr))->bits)
> X
> X#define ip_v4addr(ipaddrptr) \
> X (((ipaddr_struct *)VARDATA(ipaddrptr))->addr.ipv4_addr)
> X
> X/*
> X * Various forward declarations:
> X */
> X
> Xipaddr *ipaddr_in(char *str);
> Xchar *ipaddr_out(ipaddr *addr);
> X
> Xbool ipaddr_lt(ipaddr *a1, ipaddr *a2);
> Xbool ipaddr_le(ipaddr *a1, ipaddr *a2);
> Xbool ipaddr_eq(ipaddr *a1, ipaddr *a2);
> Xbool ipaddr_ge(ipaddr *a1, ipaddr *a2);
> Xbool ipaddr_gt(ipaddr *a1, ipaddr *a2);
> X
> Xbool ipaddr_ne(ipaddr *a1, ipaddr *a2);
> X
> Xbool ipaddr_sub(ipaddr *a1, ipaddr *a2);
> Xbool ipaddr_subeq(ipaddr *a1, ipaddr *a2);
> Xbool ipaddr_sup(ipaddr *a1, ipaddr *a2);
> Xbool ipaddr_supeq(ipaddr *a1, ipaddr *a2);
> X
> Xint4 ipaddr_cmp(ipaddr *a1, ipaddr *a2);
> X
> Xint v4bitncmp(u_int32_t a1, u_int32_t a2, int bits);
> X
> X/*
> X * IP address reader.
> X */
> X
> Xipaddr *ipaddr_in(char *src) {
> X int bits;
> X ipaddr *dst;
> X
> X dst = palloc(VARHDRSZ + sizeof(ipaddr_struct));
> X if (dst == NULL) {
> X elog(ERROR, "unable to allocate memory in ipaddr_in()");
> X return(NULL);
> X }
> X /* First, try for an IP V4 address: */
> X ip_family(dst) = AF_INET;
> X bits = inet_net_pton(ip_family(dst), src, &ip_v4addr(dst), ip_addrsize(dst));
> X if ((bits < 0) || (bits > 32)) {
> X /* Go for an IPV6 address here, before faulting out: */
> X elog(ERROR, "could not parse \"%s\"", src);
> X pfree(dst);
> X return(NULL);
> X }
> X VARSIZE(dst) = VARHDRSZ
> X + ((char *)&ip_v4addr(dst) - (char *)VARDATA(dst))
> X + ip_addrsize(dst);
> X ip_bits(dst) = bits;
> X return(dst);
> X}
> X
> X/*
> X * IP address output function.
> X */
> X
> Xchar *ipaddr_out(ipaddr *src) {
> X char *dst, tmp[sizeof("255.255.255.255/32")];
> X
> X if (ip_family(src) == AF_INET) {
> X /* It's an IP V4 address: */
> X if (inet_net_ntop(AF_INET, &ip_v4addr(src), ip_bits(src),
> X tmp, sizeof(tmp)) < 0) {
> X elog(ERROR, "unable to print address (%s)", strerror(errno));
> X return(NULL);
> X }
> X } else {
> X /* Go for an IPV6 address here, before faulting out: */
> X elog(ERROR, "unknown address family (%d)", ip_family(src));
> X return(NULL);
> X }
> X dst = palloc(strlen(tmp) + 1);
> X if (dst == NULL) {
> X elog(ERROR, "unable to allocate memory in ipaddr_out()");
> X return(NULL);
> X }
> X strcpy(dst, tmp);
> X return(dst);
> X}
> X
> X/*
> X * Boolean tests for magnitude. Add V4/V6 testing!
> X */
> X
> Xbool ipaddr_lt(ipaddr *a1, ipaddr *a2) {
> X if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) {
> X int order = v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2));
> X return((order < 0) || ((order == 0) && (ip_bits(a1) < ip_bits(a2))));
> X } else {
> X /* Go for an IPV6 address here, before faulting out: */
> X elog(ERROR, "cannot compare address families %d and %d",
> X ip_family(a1), ip_family(a2));
> X return(FALSE);
> X }
> X}
> X
> Xbool ipaddr_le(ipaddr *a1, ipaddr *a2) {
> X return(ipaddr_lt(a1, a2) || ipaddr_eq(a1, a2));
> X}
> X
> Xbool ipaddr_eq(ipaddr *a1, ipaddr *a2) {
> X if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) {
> X return((ip_bits(a1) == ip_bits(a2))
> X && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0));
> X } else {
> X /* Go for an IPV6 address here, before faulting out: */
> X elog(ERROR, "cannot compare address families %d and %d",
> X ip_family(a1), ip_family(a2));
> X return(FALSE);
> X }
> X}
> X
> Xbool ipaddr_ge(ipaddr *a1, ipaddr *a2) {
> X return(ipaddr_gt(a1, a2) || ipaddr_eq(a1, a2));
> X}
> X
> Xbool ipaddr_gt(ipaddr *a1, ipaddr *a2) {
> X if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) {
> X int order = v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2));
> X return((order > 0) || ((order == 0) && (ip_bits(a1) > ip_bits(a2))));
> X } else {
> X /* Go for an IPV6 address here, before faulting out: */
> X elog(ERROR, "cannot compare address families %d and %d",
> X ip_family(a1), ip_family(a2));
> X return(FALSE);
> X }
> X}
> X
> Xbool ipaddr_ne(ipaddr *a1, ipaddr *a2) {
> X return(!ipaddr_eq(a1, a2));
> X}
> X
> Xbool ipaddr_sub(ipaddr *a1, ipaddr *a2) {
> X if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) {
> X return((ip_bits(a1) > ip_bits(a2))
> X && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0));
> X } else {
> X /* Go for an IPV6 address here, before faulting out: */
> X elog(ERROR, "cannot compare address families %d and %d",
> X ip_family(a1), ip_family(a2));
> X return(FALSE);
> X }
> X}
> X
> Xbool ipaddr_subeq(ipaddr *a1, ipaddr *a2) {
> X if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) {
> X return((ip_bits(a1) >= ip_bits(a2))
> X && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0));
> X } else {
> X /* Go for an IPV6 address here, before faulting out: */
> X elog(ERROR, "cannot compare address families %d and %d",
> X ip_family(a1), ip_family(a2));
> X return(FALSE);
> X }
> X}
> X
> Xbool ipaddr_sup(ipaddr *a1, ipaddr *a2) {
> X if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) {
> X return((ip_bits(a1) < ip_bits(a2))
> X && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0));
> X } else {
> X /* Go for an IPV6 address here, before faulting out: */
> X elog(ERROR, "cannot compare address families %d and %d",
> X ip_family(a1), ip_family(a2));
> X return(FALSE);
> X }
> X}
> X
> Xbool ipaddr_supeq(ipaddr *a1, ipaddr *a2) {
> X if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) {
> X return((ip_bits(a1) <= ip_bits(a2))
> X && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0));
> X } else {
> X /* Go for an IPV6 address here, before faulting out: */
> X elog(ERROR, "cannot compare address families %d and %d",
> X ip_family(a1), ip_family(a2));
> X return(FALSE);
> X }
> X}
> X
> X/*
> X * Comparison function for sorting. Add V4/V6 testing!
> X */
> X
> Xint4 ipaddr_cmp(ipaddr *a1, ipaddr *a2) {
> X if (ntohl(ip_v4addr(a1)) < ntohl(ip_v4addr(a2))) {
> X return(-1);
> X } else if (ntohl(ip_v4addr(a1)) > ntohl(ip_v4addr(a2))) {
> X return(1);
> X }
> X return 0;
> X}
> X
> X/*
> X * Bitwise comparison for V4 addresses. Add V6 implementation!
> X */
> X
> Xint v4bitncmp(u_int32_t a1, u_int32_t a2, int bits) {
> X unsigned long mask = 0;
> X int i;
> X for (i = 0; i < bits; i++) {
> X mask = (mask >> 1) | 0x80000000;
> X }
> X a1 = ntohl(a1);
> X a2 = ntohl(a2);
> X if ((a1 & mask) < (a2 & mask)) {
> X return(-1);
> X } else if ((a1 & mask) > (a2 & mask)) {
> X return(1);
> X }
> X return(0);
> X}
> X
> X/*
> X * eof
> X */
> END-of-ip.c
> echo x - ip.sql.in
> sed 's/^X//' >ip.sql.in << 'END-of-ip.sql.in'
> X--
> X-- PostgreSQL code for IP addresses.
> X--
> X-- $Id: ip.sql.in,v 1.2 1998/09/08 12:10:45 tih Exp $
> X--
> X
> Xload 'TARGET/ip.so';
> X
> X--
> X-- Input and output functions and the type itself:
> X--
> X
> Xcreate function ipaddr_in(opaque)
> X returns opaque
> X as 'TARGET/ip.so'
> X language 'c';
> X
> Xcreate function ipaddr_out(opaque)
> X returns opaque
> X as 'TARGET/ip.so'
> X language 'c';
> X
> Xcreate type ipaddr (
> X internallength = variable,
> X externallength = variable,
> X input = ipaddr_in,
> X output = ipaddr_out
> X);
> X
> X--
> X-- The various boolean tests:
> X--
> X
> Xcreate function ipaddr_lt(ipaddr, ipaddr)
> X returns bool
> X as 'TARGET/ip.so'
> X language 'c';
> X
> Xcreate function ipaddr_le(ipaddr, ipaddr)
> X returns bool
> X as 'TARGET/ip.so'
> X language 'c';
> X
> Xcreate function ipaddr_eq(ipaddr, ipaddr)
> X returns bool
> X as 'TARGET/ip.so'
> X language 'c';
> X
> Xcreate function ipaddr_ge(ipaddr, ipaddr)
> X returns bool
> X as 'TARGET/ip.so'
> X language 'c';
> X
> Xcreate function ipaddr_gt(ipaddr, ipaddr)
> X returns bool
> X as 'TARGET/ip.so'
> X language 'c';
> X
> Xcreate function ipaddr_ne(ipaddr, ipaddr)
> X returns bool
> X as 'TARGET/ip.so'
> X language 'c';
> X
> Xcreate function ipaddr_sub(ipaddr, ipaddr)
> X returns bool
> X as 'TARGET/ip.so'
> X language 'c';
> X
> Xcreate function ipaddr_subeq(ipaddr, ipaddr)
> X returns bool
> X as 'TARGET/ip.so'
> X language 'c';
> X
> Xcreate function ipaddr_sup(ipaddr, ipaddr)
> X returns bool
> X as 'TARGET/ip.so'
> X language 'c';
> X
> Xcreate function ipaddr_supeq(ipaddr, ipaddr)
> X returns bool
> X as 'TARGET/ip.so'
> X language 'c';
> X
> Xcreate function ipaddr_cmp(ipaddr, ipaddr)
> X returns int4
> X as 'TARGET/ip.so'
> X language 'c';
> X
> X--
> X-- Now the operators. Note how some of the parameters to some
> X-- of the 'create operator' commands are commented out. This
> X-- is because they reference as yet undefined operators, and
> X-- will be implicitly defined when those are, further down.
> X--
> X
> Xcreate operator < (
> X leftarg = ipaddr,
> X rightarg = ipaddr,
> X-- negator = >=,
> X restrict = intltsel,
> X join = intltjoinsel,
> X procedure = ipaddr_lt
> X);
> X
> Xcreate operator <= (
> X leftarg = ipaddr,
> X rightarg = ipaddr,
> X-- negator = >,
> X restrict = intltsel,
> X join = intltjoinsel,
> X procedure = ipaddr_le
> X);
> X
> Xcreate operator = (
> X leftarg = ipaddr,
> X rightarg = ipaddr,
> X commutator = =,
> X-- negator = <>,
> X restrict = eqsel,
> X join = eqjoinsel,
> X procedure = ipaddr_eq
> X);
> X
> Xcreate operator >= (
> X leftarg = ipaddr,
> X rightarg = ipaddr,
> X negator = <,
> X restrict = intgtsel,
> X join = intgtjoinsel,
> X procedure = ipaddr_ge
> X);
> X
> Xcreate operator > (
> X leftarg = ipaddr,
> X rightarg = ipaddr,
> X negator = <=,
> X restrict = intgtsel,
> X join = intgtjoinsel,
> X procedure = ipaddr_gt
> X);
> X
> Xcreate operator <> (
> X leftarg = ipaddr,
> X rightarg = ipaddr,
> X negator = =,
> X restrict = neqsel,
> X join = neqjoinsel,
> X procedure = ipaddr_ne
> X);
> X
> Xcreate operator << (
> X leftarg = ipaddr,
> X rightarg = ipaddr,
> X procedure = ipaddr_sub
> X);
> X
> Xcreate operator <<= (
> X leftarg = ipaddr,
> X rightarg = ipaddr,
> X procedure = ipaddr_subeq
> X);
> X
> Xcreate operator >> (
> X leftarg = ipaddr,
> X rightarg = ipaddr,
> X procedure = ipaddr_sup
> X);
> X
> Xcreate operator >>= (
> X leftarg = ipaddr,
> X rightarg = ipaddr,
> X procedure = ipaddr_supeq
> X);
> X
> X--
> X-- Finally, make it possible to do btree indexing on IP addresses.
> X--
> X
> Xbegin;
> X
> Xcreate table tmp_op (oprname name, opi int2);
> X
> Xinsert into tmp_op values ('<', 1);
> Xinsert into tmp_op values ('<=', 2);
> Xinsert into tmp_op values ('=', 3);
> Xinsert into tmp_op values ('>=', 4);
> Xinsert into tmp_op values ('>', 5);
> X
> Xdelete from pg_opclass
> X where opcname = 'ipaddr_ops';
> X
> Xinsert into pg_opclass (opcname, opcdeftype)
> X select 'ipaddr_ops', oid from pg_type
> X where typname = 'ipaddr';
> X
> Xselect o.oid as opoid, o.oprname
> X into table ipaddr_tmp
> X from pg_operator o, pg_type t
> X where o.oprleft = t.oid and
> X o.oprright = t.oid and
> X t.typname = 'ipaddr';
> X
> Xinsert into pg_amop (amopid, amopclaid, amopopr, amopstrategy,
> X amopselect, amopnpages)
> X select am.oid, opcl.oid, c.opoid, t.opi,
> X 'btreesel'::regproc, 'btreenpage'::regproc
> X from pg_am am, pg_opclass opcl, ipaddr_tmp c, tmp_op t
> X where t.oprname = c.oprname and
> X amname = 'btree' and opcname = 'ipaddr_ops';
> X
> Xinsert into pg_amproc (amid, amopclaid, amproc, amprocnum)
> X select pgam.oid, opc.oid, prc.oid, '1'::int2
> X from pg_am pgam, pg_opclass opc, pg_proc prc
> X where prc.proname = 'ipaddr_cmp' and
> X pgam.amname = 'btree' and
> X opc.opcname = 'ipaddr_ops';
> X
> Xdrop table tmp_op;
> Xdrop table ipaddr_tmp;
> X
> Xcommit;
> X
> X--
> X-- eof
> X--
> END-of-ip.sql.in
> echo x - mac.c
> sed 's/^X//' >mac.c << 'END-of-mac.c'
> X/*
> X * PostgreSQL type definitions for MAC addresses.
> X *
> X * $Id: mac.c,v 1.1 1998/09/07 12:31:18 tih Exp $
> X */
> X
> X#include <stdio.h>
> X
> X#include <postgres.h>
> X#include <utils/palloc.h>
> X
> X#include "mac.h"
> X
> X/*
> X * This is the internal storage format for MAC addresses:
> X */
> X
> Xtypedef struct macaddr {
> X unsigned char a;
> X unsigned char b;
> X unsigned char c;
> X unsigned char d;
> X unsigned char e;
> X unsigned char f;
> X} macaddr;
> X
> X/*
> X * Various forward declarations:
> X */
> X
> Xmacaddr *macaddr_in(char *str);
> Xchar *macaddr_out(macaddr *addr);
> X
> Xbool macaddr_lt(macaddr *a1, macaddr *a2);
> Xbool macaddr_le(macaddr *a1, macaddr *a2);
> Xbool macaddr_eq(macaddr *a1, macaddr *a2);
> Xbool macaddr_ge(macaddr *a1, macaddr *a2);
> Xbool macaddr_gt(macaddr *a1, macaddr *a2);
> X
> Xbool macaddr_ne(macaddr *a1, macaddr *a2);
> X
> Xint4 macaddr_cmp(macaddr *a1, macaddr *a2);
> X
> Xtext *macaddr_manuf(macaddr *addr);
> X
> X/*
> X * Utility macros used for sorting and comparing:
> X */
> X
> X#define hibits(addr) \
> X ((unsigned long)((addr->a<<16)|(addr->b<<8)|(addr->c)))
> X
> X#define lobits(addr) \
> X ((unsigned long)((addr->c<<16)|(addr->e<<8)|(addr->f)))
> X
> X/*
> X * MAC address reader. Accepts several common notations.
> X */
> X
> Xmacaddr *macaddr_in(char *str) {
> X int a, b, c, d, e, f;
> X macaddr *result;
> X int count;
> X
> X if (strlen(str) > 0) {
> X
> X count = sscanf(str, "%x:%x:%x:%x:%x:%x", &a, &b, &c, &d, &e, &f);
> X if (count != 6)
> X count = sscanf(str, "%x-%x-%x-%x-%x-%x", &a, &b, &c, &d, &e, &f);
> X if (count != 6)
> X count = sscanf(str, "%2x%2x%2x:%2x%2x%2x", &a, &b, &c, &d, &e, &f);
> X if (count != 6)
> X count = sscanf(str, "%2x%2x%2x-%2x%2x%2x", &a, &b, &c, &d, &e, &f);
> X if (count != 6)
> X count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x", &a, &b, &c, &d, &e, &f);
> X
> X if (count != 6) {
> X elog(ERROR, "macaddr_in: error in parsing \"%s\"", str);
> X return(NULL);
> X }
> X
> X if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
> X (c < 0) || (c > 255) || (d < 0) || (d > 255) ||
> X (e < 0) || (e > 255) || (f < 0) || (f > 255)) {
> X elog(ERROR, "macaddr_in: illegal address \"%s\"", str);
> X return(NULL);
> X }
> X } else {
> X a = b = c = d = e = f = 0; /* special case for missing address */
> X }
> X
> X result = (macaddr *)palloc(sizeof(macaddr));
> X
> X result->a = a;
> X result->b = b;
> X result->c = c;
> X result->d = d;
> X result->e = e;
> X result->f = f;
> X
> X return(result);
> X}
> X
> X/*
> X * MAC address output function. Fixed format.
> X */
> X
> Xchar *macaddr_out(macaddr *addr) {
> X char *result;
> X
> X if (addr == NULL)
> X return(NULL);
> X
> X result = (char *)palloc(32);
> X
> X if ((hibits(addr) > 0) || (lobits(addr) > 0)) {
> X sprintf(result, "%02x:%02x:%02x:%02x:%02x:%02x",
> X addr->a, addr->b, addr->c, addr->d, addr->e, addr->f);
> X } else {
> X result[0] = 0; /* special case for missing address */
> X }
> X return(result);
> X}
> X
> X/*
> X * Boolean tests.
> X */
> X
> Xbool macaddr_lt(macaddr *a1, macaddr *a2) {
> X return((hibits(a1) < hibits(a2)) ||
> X ((hibits(a1) == hibits(a2)) && lobits(a1) < lobits(a2)));
> X};
> X
> Xbool macaddr_le(macaddr *a1, macaddr *a2) {
> X return((hibits(a1) < hibits(a2)) ||
> X ((hibits(a1) == hibits(a2)) && lobits(a1) <= lobits(a2)));
> X};
> X
> Xbool macaddr_eq(macaddr *a1, macaddr *a2) {
> X return ((hibits(a1) == hibits(a2)) && (lobits(a1) == lobits(a2)));
> X};
> X
> Xbool macaddr_ge(macaddr *a1, macaddr *a2) {
> X return((hibits(a1) > hibits(a2)) ||
> X ((hibits(a1) == hibits(a2)) && lobits(a1) >= lobits(a2)));
> X};
> X
> Xbool macaddr_gt(macaddr *a1, macaddr *a2) {
> X return((hibits(a1) > hibits(a2)) ||
> X ((hibits(a1) == hibits(a2)) && lobits(a1) > lobits(a2)));
> X};
> X
> Xbool macaddr_ne(macaddr *a1, macaddr *a2) {
> X return ((hibits(a1) != hibits(a2)) || (lobits(a1) != lobits(a2)));
> X};
> X
> X/*
> X * Comparison function for sorting:
> X */
> X
> Xint4 macaddr_cmp(macaddr *a1, macaddr *a2) {
> X if (hibits(a1) < hibits(a2))
> X return -1;
> X else if (hibits(a1) > hibits(a2))
> X return 1;
> X else if (lobits(a1) < lobits(a2))
> X return -1;
> X else if (lobits(a1) > lobits(a2))
> X return 1;
> X else
> X return 0;
> X}
> X
> X/*
> X * The special manufacturer fetching function. See "mac.h".
> X */
> X
> Xtext *macaddr_manuf(macaddr *addr) {
> X manufacturer *manuf;
> X int length;
> X text *result;
> X
> X for (manuf = manufacturers; manuf->name != NULL; manuf++) {
> X if ((manuf->a == addr->a) &&
> X (manuf->b == addr->b) &&
> X (manuf->c == addr->c))
> X break;
> X }
> X if (manuf->name == NULL) {
> X result = palloc(VARHDRSZ + 1);
> X memset(result, 0, VARHDRSZ + 1);
> X VARSIZE(result) = VARHDRSZ + 1;
> X } else {
> X length = strlen(manuf->name) + 1;
> X result = palloc(length + VARHDRSZ);
> X memset(result, 0, length + VARHDRSZ);
> X VARSIZE(result) = length + VARHDRSZ;
> X memcpy(VARDATA(result), manuf->name, length);
> X }
> X return result;
> X}
> X
> X/*
> X * eof
> X */
> END-of-mac.c
> echo x - mac.h
> sed 's/^X//' >mac.h << 'END-of-mac.h'
> X/*
> X * PostgreSQL type definitions for MAC addresses.
> X *
> X * $Id: mac.h,v 1.1 1998/09/07 12:31:22 tih Exp $
> X */
> X
> Xtypedef struct manufacturer {
> X unsigned char a;
> X unsigned char b;
> X unsigned char c;
> X char *name;
> X} manufacturer;
> X
> Xmanufacturer manufacturers[] = {
> X {0x00, 0x00, 0x0C, "Cisco"},
> X {0x00, 0x00, 0x0E, "Fujitsu"},
> X {0x00, 0x00, 0x0F, "NeXT"},
> X {0x00, 0x00, 0x10, "Sytek"},
> X {0x00, 0x00, 0x1D, "Cabletron"},
> X {0x00, 0x00, 0x20, "DIAB"},
> X {0x00, 0x00, 0x22, "Visual Technology"},
> X {0x00, 0x00, 0x2A, "TRW"},
> X {0x00, 0x00, 0x32, "GPT Limited"},
> X {0x00, 0x00, 0x5A, "S & Koch"},
> X {0x00, 0x00, 0x5E, "IANA"},
> X {0x00, 0x00, 0x65, "Network General"},
> X {0x00, 0x00, 0x6B, "MIPS"},
> X {0x00, 0x00, 0x77, "MIPS"},
> X {0x00, 0x00, 0x7A, "Ardent"},
> X {0x00, 0x00, 0x89, "Cayman Systems"},
> X {0x00, 0x00, 0x93, "Proteon"},
> X {0x00, 0x00, 0x9F, "Ameristar Technology"},
> X {0x00, 0x00, 0xA2, "Wellfleet"},
> X {0x00, 0x00, 0xA3, "Network Application Technology"},
> X {0x00, 0x00, 0xA6, "Network General"},
> X {0x00, 0x00, 0xA7, "NCD"},
> X {0x00, 0x00, 0xA9, "Network Systems"},
> X {0x00, 0x00, 0xAA, "Xerox"},
> X {0x00, 0x00, 0xB3, "CIMLinc"},
> X {0x00, 0x00, 0xB7, "Dove Fastnet"},
> X {0x00, 0x00, 0xBC, "Allen-Bradley"},
> X {0x00, 0x00, 0xC0, "Western Digital"},
> X {0x00, 0x00, 0xC5, "Farallon"},
> X {0x00, 0x00, 0xC6, "Hewlett-Packard"},
> X {0x00, 0x00, 0xC8, "Altos"},
> X {0x00, 0x00, 0xC9, "Emulex"},
> X {0x00, 0x00, 0xD7, "Dartmouth College"},
> X {0x00, 0x00, 0xD8, "3Com (?)"},
> X {0x00, 0x00, 0xDD, "Gould"},
> X {0x00, 0x00, 0xDE, "Unigraph"},
> X {0x00, 0x00, 0xE2, "Acer Counterpoint"},
> X {0x00, 0x00, 0xEF, "Alantec"},
> X {0x00, 0x00, 0xFD, "High Level Hardware"},
> X {0x00, 0x01, 0x02, "BBN internal usage"},
> X {0x00, 0x20, 0xAF, "3Com"},
> X {0x00, 0x17, 0x00, "Kabel"},
> X {0x00, 0x80, 0x64, "Wyse Technology"},
> X {0x00, 0x80, 0x2B, "IMAC (?)"},
> X {0x00, 0x80, 0x2D, "Xylogics, Inc."},
> X {0x00, 0x80, 0x8C, "Frontier Software Development"},
> X {0x00, 0x80, 0xC2, "IEEE 802.1 Committee"},
> X {0x00, 0x80, 0xD3, "Shiva"},
> X {0x00, 0xAA, 0x00, "Intel"},
> X {0x00, 0xDD, 0x00, "Ungermann-Bass"},
> X {0x00, 0xDD, 0x01, "Ungermann-Bass"},
> X {0x02, 0x07, 0x01, "Racal InterLan"},
> X {0x02, 0x04, 0x06, "BBN internal usage"},
> X {0x02, 0x60, 0x86, "Satelcom MegaPac"},
> X {0x02, 0x60, 0x8C, "3Com"},
> X {0x02, 0xCF, 0x1F, "CMC"},
> X {0x08, 0x00, 0x02, "3Com"},
> X {0x08, 0x00, 0x03, "ACC"},
> X {0x08, 0x00, 0x05, "Symbolics"},
> X {0x08, 0x00, 0x08, "BBN"},
> X {0x08, 0x00, 0x09, "Hewlett-Packard"},
> X {0x08, 0x00, 0x0A, "Nestar Systems"},
> X {0x08, 0x00, 0x0B, "Unisys"},
> X {0x08, 0x00, 0x11, "Tektronix"},
> X {0x08, 0x00, 0x14, "Excelan"},
> X {0x08, 0x00, 0x17, "NSC"},
> X {0x08, 0x00, 0x1A, "Data General"},
> X {0x08, 0x00, 0x1B, "Data General"},
> X {0x08, 0x00, 0x1E, "Apollo"},
> X {0x08, 0x00, 0x20, "Sun"},
> X {0x08, 0x00, 0x22, "NBI"},
> X {0x08, 0x00, 0x25, "CDC"},
> X {0x08, 0x00, 0x26, "Norsk Data"},
> X {0x08, 0x00, 0x27, "PCS Computer Systems GmbH"},
> X {0x08, 0x00, 0x28, "Texas Instruments"},
> X {0x08, 0x00, 0x2B, "DEC"},
> X {0x08, 0x00, 0x2E, "Metaphor"},
> X {0x08, 0x00, 0x2F, "Prime Computer"},
> X {0x08, 0x00, 0x36, "Intergraph"},
> X {0x08, 0x00, 0x37, "Fujitsu-Xerox"},
> X {0x08, 0x00, 0x38, "Bull"},
> X {0x08, 0x00, 0x39, "Spider Systems"},
> X {0x08, 0x00, 0x41, "DCA Digital Comm. Assoc."},
> X {0x08, 0x00, 0x45, "Xylogics (?)"},
> X {0x08, 0x00, 0x46, "Sony"},
> X {0x08, 0x00, 0x47, "Sequent"},
> X {0x08, 0x00, 0x49, "Univation"},
> X {0x08, 0x00, 0x4C, "Encore"},
> X {0x08, 0x00, 0x4E, "BICC"},
> X {0x08, 0x00, 0x56, "Stanford University"},
> X {0x08, 0x00, 0x58, "DECsystem 20 (?)"},
> X {0x08, 0x00, 0x5A, "IBM"},
> X {0x08, 0x00, 0x67, "Comdesign"},
> X {0x08, 0x00, 0x68, "Ridge"},
> X {0x08, 0x00, 0x69, "Silicon Graphics"},
> X {0x08, 0x00, 0x6E, "Concurrent"},
> X {0x08, 0x00, 0x75, "DDE"},
> X {0x08, 0x00, 0x7C, "Vitalink"},
> X {0x08, 0x00, 0x80, "XIOS"},
> X {0x08, 0x00, 0x86, "Imagen/QMS"},
> X {0x08, 0x00, 0x87, "Xyplex"},
> X {0x08, 0x00, 0x89, "Kinetics"},
> X {0x08, 0x00, 0x8B, "Pyramid"},
> X {0x08, 0x00, 0x8D, "XyVision"},
> X {0x08, 0x00, 0x90, "Retix Inc"},
> X {0x48, 0x44, 0x53, "HDS (?)"},
> X {0x80, 0x00, 0x10, "AT&T"},
> X {0xAA, 0x00, 0x00, "DEC"},
> X {0xAA, 0x00, 0x01, "DEC"},
> X {0xAA, 0x00, 0x02, "DEC"},
> X {0xAA, 0x00, 0x03, "DEC"},
> X {0xAA, 0x00, 0x04, "DEC"},
> X {0x00, 0x00, 0x00, NULL}
> X};
> X
> X/*
> X * eof
> X */
> END-of-mac.h
> echo x - mac.sql.in
> sed 's/^X//' >mac.sql.in << 'END-of-mac.sql.in'
> X--
> X-- PostgreSQL code for MAC addresses.
> X--
> X-- $Id: mac.sql.in,v 1.2 1998/09/08 12:11:18 tih Exp $
> X--
> X
> Xload 'TARGET/mac.so';
> X
> X--
> X-- Input and output functions and the type itself:
> X--
> X
> Xcreate function macaddr_in(opaque)
> X returns opaque
> X as 'TARGET/mac.so'
> X language 'c';
> X
> Xcreate function macaddr_out(opaque)
> X returns opaque
> X as 'TARGET/mac.so'
> X language 'c';
> X
> Xcreate type macaddr (
> X internallength = 6,
> X externallength = variable,
> X input = macaddr_in,
> X output = macaddr_out
> X);
> X
> X--
> X-- The boolean tests:
> X--
> X
> Xcreate function macaddr_lt(macaddr, macaddr)
> X returns bool
> X as 'TARGET/mac.so'
> X language 'c';
> X
> Xcreate function macaddr_le(macaddr, macaddr)
> X returns bool
> X as 'TARGET/mac.so'
> X language 'c';
> X
> Xcreate function macaddr_eq(macaddr, macaddr)
> X returns bool
> X as 'TARGET/mac.so'
> X language 'c';
> X
> Xcreate function macaddr_ge(macaddr, macaddr)
> X returns bool
> X as 'TARGET/mac.so'
> X language 'c';
> X
> Xcreate function macaddr_gt(macaddr, macaddr)
> X returns bool
> X as 'TARGET/mac.so'
> X language 'c';
> X
> Xcreate function macaddr_ne(macaddr, macaddr)
> X returns bool
> X as 'TARGET/mac.so'
> X language 'c';
> X
> Xcreate function macaddr_cmp(macaddr, macaddr)
> X returns int4
> X as 'TARGET/mac.so'
> X language 'c';
> X
> X--
> X-- Now the operators. Note how some of the parameters to some
> X-- of the 'create operator' commands are commented out. This
> X-- is because they reference as yet undefined operators, and
> X-- will be implicitly defined when those are, further down.
> X--
> X
> Xcreate operator < (
> X leftarg = macaddr,
> X rightarg = macaddr,
> X-- negator = >=,
> X procedure = macaddr_lt
> X);
> X
> Xcreate operator <= (
> X leftarg = macaddr,
> X rightarg = macaddr,
> X-- negator = >,
> X procedure = macaddr_le
> X);
> X
> Xcreate operator = (
> X leftarg = macaddr,
> X rightarg = macaddr,
> X commutator = =,
> X-- negator = <>,
> X procedure = macaddr_eq
> X);
> X
> Xcreate operator >= (
> X leftarg = macaddr,
> X rightarg = macaddr,
> X negator = <,
> X procedure = macaddr_ge
> X);
> X
> Xcreate operator > (
> X leftarg = macaddr,
> X rightarg = macaddr,
> X negator = <=,
> X procedure = macaddr_gt
> X);
> X
> Xcreate operator <> (
> X leftarg = macaddr,
> X rightarg = macaddr,
> X negator = =,
> X procedure = macaddr_ne
> X);
> X
> X--
> X-- Finally, the special manufacurer matching function:
> X--
> X
> Xcreate function macaddr_manuf(macaddr)
> X returns text
> X as 'TARGET/mac.so'
> X language 'c';
> X
> X--
> X-- Finally, make it possible to do btree indexing on MAC addresses.
> X--
> X
> Xbegin;
> X
> Xcreate table tmp_op (oprname name, opi int2);
> X
> Xinsert into tmp_op values ('<', 1);
> Xinsert into tmp_op values ('<=', 2);
> Xinsert into tmp_op values ('=', 3);
> Xinsert into tmp_op values ('>=', 4);
> Xinsert into tmp_op values ('>', 5);
> X
> Xdelete from pg_opclass
> X where opcname = 'macaddr_ops';
> X
> Xinsert into pg_opclass (opcname, opcdeftype)
> X select 'macaddr_ops', oid from pg_type
> X where typname = 'macaddr';
> X
> Xselect o.oid as opoid, o.oprname
> X into table macaddr_tmp
> X from pg_operator o, pg_type t
> X where o.oprleft = t.oid and
> X o.oprright = t.oid and
> X t.typname = 'macaddr';
> X
> Xinsert into pg_amop (amopid, amopclaid, amopopr, amopstrategy,
> X amopselect, amopnpages)
> X select am.oid, opcl.oid, c.opoid, t.opi,
> X 'btreesel'::regproc, 'btreenpage'::regproc
> X from pg_am am, pg_opclass opcl, macaddr_tmp c, tmp_op t
> X where t.oprname = c.oprname and
> X amname = 'btree' and opcname = 'macaddr_ops';
> X
> Xinsert into pg_amproc (amid, amopclaid, amproc, amprocnum)
> X select pgam.oid, opc.oid, prc.oid, '1'::int2
> X from pg_am pgam, pg_opclass opc, pg_proc prc
> X where prc.proname = 'macaddr_cmp' and
> X pgam.amname = 'btree' and
> X opc.opcname = 'macaddr_ops';
> X
> Xdrop table tmp_op;
> Xdrop table macaddr_tmp;
> X
> Xcommit;
> X
> X--
> X-- eof
> X--
> END-of-mac.sql.in
> echo x - test.sql
> sed 's/^X//' >test.sql << 'END-of-test.sql'
> X--
> X-- A quick test of the IP address code
> X--
> X-- $Id: test.sql,v 1.2 1998/09/08 12:11:34 tih Exp $
> X--
> X
> X-- temporary table:
> Xcreate table addresses (address ipaddr);
> X
> X-- sample data from two subnets:
> Xinsert into addresses values ('158.37.96.15');
> Xinsert into addresses values ('158.37.96.16');
> Xinsert into addresses values ('158.37.96.17');
> Xinsert into addresses values ('158.37.97.15');
> Xinsert into addresses values ('158.37.97.16');
> Xinsert into addresses values ('158.37.97.17');
> Xinsert into addresses values ('158.37.98.15');
> Xinsert into addresses values ('158.37.98.16');
> Xinsert into addresses values ('158.37.98.17');
> Xinsert into addresses values ('158.37.96.150');
> Xinsert into addresses values ('158.37.96.160');
> Xinsert into addresses values ('158.37.96.170');
> Xinsert into addresses values ('158.37.97.150');
> Xinsert into addresses values ('158.37.97.160');
> Xinsert into addresses values ('158.37.97.170');
> Xinsert into addresses values ('158.37.98.150');
> Xinsert into addresses values ('158.37.98.160');
> Xinsert into addresses values ('158.37.98.170');
> X
> X-- show them all:
> Xselect * from addresses;
> X
> X-- select the ones in subnet 96:
> Xselect * from addresses where address << '158.37.96.0/24';
> X
> X-- select the ones not in subnet 96:
> Xselect * from addresses where not address << '158.37.96.0/24';
> X
> X-- select the ones in subnet 97:
> Xselect * from addresses where address << '158.37.97.0/24';
> X
> X-- select the ones not in subnet 97:
> Xselect * from addresses where not address << '158.37.97.0/24';
> X
> X-- select the ones in subnet 96 or 97, sorted:
> Xselect * from addresses where address << '158.37.96.0/23'
> X order by address;
> X
> X-- now some networks:
> Xcreate table networks (network ipaddr);
> X
> X-- now the subnets mentioned above:
> Xinsert into networks values ('158.37.96.0/24');
> Xinsert into networks values ('158.37.97.0/24');
> Xinsert into networks values ('158.37.98.0/24');
> X
> X-- select matching pairs of addresses and containing nets:
> Xselect address, network from addresses, networks
> X where address << network;
> X
> X-- tidy up:
> Xdrop table addresses;
> Xdrop table networks;
> X
> X--
> X-- eof
> X--
> END-of-test.sql
> exit
>
--
Bruce Momjian | 830 Blythe Avenue
maillist(at)candle(dot)pha(dot)pa(dot)us | Drexel Hill, Pennsylvania 19026
+ If your life is a hard drive, | (610) 353-9879(w)
+ Christ can be your backup. | (610) 853-3000(h)
From | Date | Subject | |
---|---|---|---|
Next Message | Chris Johnson | 1998-09-08 17:23:26 | Re: [GENERAL] About php and postgreSQL. |
Previous Message | Tom Ivar Helbekkmo | 1998-09-08 13:04:49 | Re: CIDR/IP types. Was: [GENERAL] big numbers |
From | Date | Subject | |
---|---|---|---|
Next Message | Bruce Momjian | 1998-09-08 15:40:16 | Re: [HACKERS] Macro From Hell |
Previous Message | Bruce Momjian | 1998-09-08 15:02:32 | Re: [HACKERS] Macro From Hell |