Thread: CIDR/IP types. Was: [GENERAL] big numbers
Bruce Momjian <maillist@candle.pha.pa.us> writes: > The person who said they were going to work on the IP type has not > responded to my requests for a status, and nothing has been added in > that area in 6.4. That would be me. What I said was that it looked like the thing to do was to pick the best ideas the three implementations available, and that I, at least, would be doing that for my local needs. I still plan to do that, but having recently become a father for the first time, and having lots of projects going at work, I haven't found time yet. Unless someone beats me to it, I will be doing this soon, and probably within the next couple of weeks, but obviously not in time for the 6.4 beta period. Besides, I have no idea how to integrate a new type as a built-in type, so someone else would have to do that. -tih -- Popularity is the hallmark of mediocrity. --Niles Crane, "Frasier"
> Bruce Momjian <maillist@candle.pha.pa.us> writes: > > > The person who said they were going to work on the IP type has not > > responded to my requests for a status, and nothing has been added in > > that area in 6.4. > > That would be me. What I said was that it looked like the thing to do > was to pick the best ideas the three implementations available, and > that I, at least, would be doing that for my local needs. I still > plan to do that, but having recently become a father for the first > time, and having lots of projects going at work, I haven't found time > yet. Unless someone beats me to it, I will be doing this soon, and > probably within the next couple of weeks, but obviously not in time > for the 6.4 beta period. Besides, I have no idea how to integrate a > new type as a built-in type, so someone else would have to do that. I would be glad to help with integrating it. We need a decision, people. Who do we want to do this, and how are we going to handle integrating this into the beta, if we want to? BTW, does pg_upgrade work for people. That may be a quick fix for the beta people to get these new system types WITHOUT dump/reload. -- Bruce Momjian | 830 Blythe Avenue maillist@candle.pha.pa.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)
> I would be glad to help with integrating it. We need a decision, > people. Who do we want to do this, and how are we going to handle > integrating this into the beta, if we want to? > > BTW, does pg_upgrade work for people. That may be a quick fix for the > beta people to get these new system types WITHOUT dump/reload. Better yet, they _should_ use pg_upgrade, so it gets some beta testing too :) I can help with making the types built-in, once there is code ready. However, until we finish tracking down the indexing problems I'd like to stay away from unrelated changes to the catalogs and backend code to avoid confusing the issue. Now that I think about it, that would have probably included the snprintf changes, since now people trying to do debugging may not be able to build with a new tree until that gets integrated... - Tom
On Fri, 4 Sep 1998, Thomas G. Lockhart wrote: > > I would be glad to help with integrating it. We need a decision, > > people. Who do we want to do this, and how are we going to handle > > integrating this into the beta, if we want to? > > > > BTW, does pg_upgrade work for people. That may be a quick fix for the > > beta people to get these new system types WITHOUT dump/reload. > > Better yet, they _should_ use pg_upgrade, so it gets some beta testing > too :) > > I can help with making the types built-in, once there is code ready. > However, until we finish tracking down the indexing problems I'd like to > stay away from unrelated changes to the catalogs and backend code to > avoid confusing the issue. > > Now that I think about it, that would have probably included the > snprintf changes, since now people trying to do debugging may not be > able to build with a new tree until that gets integrated... I'm going to be spending this afternoon on one of my Solaris 2.5.1 machines making sure that it does compile...I have to do an upgrade here anyway :) Well, not "here", but at work...
> > I would be glad to help with integrating it. We need a decision, > > people. Who do we want to do this, and how are we going to handle > > integrating this into the beta, if we want to? > > > > BTW, does pg_upgrade work for people. That may be a quick fix for the > > beta people to get these new system types WITHOUT dump/reload. > > Better yet, they _should_ use pg_upgrade, so it gets some beta testing > too :) > > I can help with making the types built-in, once there is code ready. > However, until we finish tracking down the indexing problems I'd like to > stay away from unrelated changes to the catalogs and backend code to > avoid confusing the issue. > > Now that I think about it, that would have probably included the > snprintf changes, since now people trying to do debugging may not be > able to build with a new tree until that gets integrated... Yes, we are definately on hold until the indexing this is fixed. -- Bruce Momjian | 830 Blythe Avenue maillist@candle.pha.pa.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)
> Bruce Momjian <maillist@candle.pha.pa.us> writes: > > > The person who said they were going to work on the IP type has not > > responded to my requests for a status, and nothing has been added in > > that area in 6.4. > > That would be me. What I said was that it looked like the thing to do > was to pick the best ideas the three implementations available, and > that I, at least, would be doing that for my local needs. I still > plan to do that, but having recently become a father for the first > time, and having lots of projects going at work, I haven't found time > yet. Unless someone beats me to it, I will be doing this soon, and > probably within the next couple of weeks, but obviously not in time > for the 6.4 beta period. Besides, I have no idea how to integrate a > new type as a built-in type, so someone else would have to do that. Tom, Paul Vixie has said he can work on it, and in fact he already sent in his version a month ago. I just had a baby three months ago, so I know how busy you must be. Unfortunately, there are few people who can integrate Paul's stuff with the current ip_and_mac code, to get the best of both. I would hate to throw out the ip_and_mac stuff without knowing if it has certain advantages over his in certain areas. I can take care of putting the code into the main PostgreSQL system, but I need someone to give me a definitive cidr/ip type that I can integrate. People really want this for 6.4. We are in beta, but we can add this type IF we can get it integrated within the next week or ten days. When do you think you can you look over both versions, and send me one good version to work with? I can take it from there, and Paul and I can work out any bugs in the code. Even if you just say, "Paul's is better, throw out ip_and_mac", that is all we need. -- Bruce Momjian | 830 Blythe Avenue maillist@candle.pha.pa.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)
> I can take care of putting the code into the main PostgreSQL system, but > I need someone to give me a definitive cidr/ip type that I can > integrate. > > People really want this for 6.4. We are in beta, but we can add this > type IF we can get it integrated within the next week or ten days. > > When do you think you can you look over both versions, and send me one > good version to work with? > > I can take it from there, and Paul and I can work out any bugs in the > code. > > Even if you just say, "Paul's is better, throw out ip_and_mac", that is > all we need. i don't think it's that clear cut. my type is intended for layer 3 applications (IP) where either hosts or networks (or subnets including variable-width subnets) need to be used as keys. the ip_and_mac type is host-only but has an unfortunate bridging between layer 3 and layer 2. in my opinion these are separate types, and since cidr is ready to go in we ought to defer ip_and_mac to 6.5, and refocus it on layer 2 applications. consider an ARP or DHCP table, which maps between layer 3 and layer 2. having a type optimized for layer 3 and a different type optimized for layer 2 creates no ugliness in my mind, and in fact serves the only need i can imagine better than a single multihedral type would do. note that cidr as supplied is capable of holding ipv6, which is also a layer 3 entity. changing the name from CIDR to INET would be ok by me, but making a type which is capable of holding either a layer 3 entity or a layer 2 one would create semantic tension in my mind about it.
On Fri, 4 Sep 1998, Bruce Momjian wrote: > Unfortunately, there are few people who can integrate Paul's stuff with > the current ip_and_mac code, to get the best of both. I would hate to > throw out the ip_and_mac stuff without knowing if it has certain > advantages over his in certain areas. Can we integrate Paul's CIDR type to give us the base, leave the ip_and_mac stuff in contrib and then once Tom has a spare moment between feedings *grin* we can get what is in the ip_and_mac stuff integrated? > Even if you just say, "Paul's is better, throw out ip_and_mac", that is > all we need. That woudn't be wise...Paul's stuff focuses on the ip aspect of ip_and_mac, not the the _and_mac part, which I feel to be as valuable, especially in a DHCP environment :)
On Fri, Sep 04, 1998 at 02:15:55PM -0400, Bruce Momjian wrote: > > plan to do that, but having recently become a father for the first Congrats Mark. How do you feel getting up each night? :-) > Tom, Paul Vixie has said he can work on it, and in fact he already sent > in his version a month ago. I just had a baby three months ago, so I > know how busy you must be. Oops, missed that. Congrats to you also, Bruce. Michael -- Michael Meskes meskes@online-club.de, meskes@debian.org Go SF49ers! Go Rhein Fire! Use Debian GNU/Linux!
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@TARGET@${TARGET}/modules@ > ip.sql X Xmac.sql: mac.sql.in X cat mac.sql.in | sed s@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@nhh.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
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@TARGET@${TARGET}/modules@ > ip.sql > X > Xmac.sql: mac.sql.in > X cat mac.sql.in | sed s@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@nhh.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@candle.pha.pa.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)
golden! ship that puppy!
Merged into the current source tree. Please test. > Bruce Momjian <maillist@candle.pha.pa.us> writes: > > > Is this the version you want me to install in the current source tree? > > Yup. It seems to work right, so it's what I'm using right now. As > soon as I've got an IPV6 kit installed here, I'll expand it with code > to handle that data type -- as you can see, I've left comments all > over the code showing what needs to be done for that. I reckon the > thing to do is for you to get it properly into the tree, and then I'll > do further maintenance on that code, and send patches. > > The SQL code to set up indexing capability doesn't work after your > changes to add OIDs to various names, but I guess that's irrelevant > when you integrate it into the base system, right? As for the MAC > level ethernet address stuff, if you want to add that as well, I guess > we should consider replacing the hard-coded table of manufacturers > with a table in template1 -- that is the SQL way, after all. Also, > the names of these types should maybe be changed? I use "ipaddr" and > "macaddr", but I can't remember if consensus was reached on whether > the IP address data type should be "cidr", or "inet", or what... If > you want me to go through the code and change that before you do the > integration, just let me know. > > -tih > -- > Popularity is the hallmark of mediocrity. --Niles Crane, "Frasier" > -- Bruce Momjian | http://www.op.net/~candle maillist@candle.pha.pa.us | (610) 853-3000 + If your life is a hard drive, | 830 Blythe Avenue + Christ can be your backup. | Drexel Hill, Pennsylvania 19026
On Sat, 3 Oct 1998, Bruce Momjian wrote: > Merged into the current source tree. Please test. > > > > Bruce Momjian <maillist@candle.pha.pa.us> writes: > > > > > Is this the version you want me to install in the current source tree? > > > > Yup. It seems to work right, so it's what I'm using right now. As > > soon as I've got an IPV6 kit installed here, I'll expand it with code > > to handle that data type -- as you can see, I've left comments all > > over the code showing what needs to be done for that. I reckon the > > thing to do is for you to get it properly into the tree, and then I'll > > do further maintenance on that code, and send patches. > > > > The SQL code to set up indexing capability doesn't work after your > > changes to add OIDs to various names, but I guess that's irrelevant > > when you integrate it into the base system, right? As for the MAC > > level ethernet address stuff, if you want to add that as well, I guess > > we should consider replacing the hard-coded table of manufacturers > > with a table in template1 -- that is the SQL way, after all. Also, > > the names of these types should maybe be changed? I use "ipaddr" and > > "macaddr", but I can't remember if consensus was reached on whether > > the IP address data type should be "cidr", or "inet", or what... If *Please* make the appropriate changes and submit a patch...it should be listed as CIDR, not as IPADDR. MACADDR, IMHO, is okay, as its the only way I've ever heard of it being referred...but I do not consider IPADDR to be correct terminology... Marc G. Fournier scrappy@hub.org Systems Administrator @ hub.org scrappy@{postgresql|isc}.org ICQ#7615664
> *Please* make the appropriate changes and submit a patch...it > should be listed as CIDR, not as IPADDR. MACADDR, IMHO, is okay, as its > the only way I've ever heard of it being referred...but I do not consider > IPADDR to be correct terminology... That is OK, but just let me that CIDR is for networks addresses, and this type supports both host and network addresses. Attached is a message from Paul Vixie mentioning this issue. It argues for the use of INET, rather than CIDR or IPADDR. --------------------------------------------------------------------------- Replies to three messages here. > From: Bruce Momjian <maillist@candle.pha.pa.us> > Date: Tue, 21 Jul 1998 01:13:34 -0400 (EDT) > > The only problem is that if we assume /32, how do we auto-netmask class > A/B/C addresses? I guess we don't. If they want a netmask, they are > going to have to specify it in cidr format. Right. But read on -- what you're calling a netmask is really a prefix length, and I think there's some confusion as to what it is. > I will be honest. I always found the network/host IP address > distinction to be very unclearly outlined in old/non-cidr address > displays, and this causes major confusion for me when trying to figure > out how things are configured. Me too. > I like INET too. It is up to you. How do folks feel about polymorphism between IPv4 and IPv6? Should we (a) make it work (either by making internal_length=10 or going variable length) or (b) just make this thing IPv4 only and take care of IPv6 separately/later? I've started to wonder if we ought to call the type INET and limit it to V4. (In the C socket bindings, IPv6 addresses are in_addr6 / sockaddr_in6, and the address family is AF_INET6 -- I don't know whether to plan on reflecting this in the postgres types, i.e., use a separate one for IPv6, or not.) > From: Bruce Momjian <maillist@candle.pha.pa.us> > Date: Tue, 21 Jul 1998 01:30:05 -0400 (EDT) > > > ... but why would you want to know the mantissa without the scale? > > I guess I thought someone might want to have ipaddr() and netmask() > functions so they can do: > > x = 192.7.34.21/24 > ipaddr(x) -> 192.7.34.21 > netmask(x) -> 255.255.255.0 This is the downreference from above. It does not work that way. /24 is not a shorthand for specifying a netmask -- in CIDR, it's a "prefix length". That means "192.7.34.21/24" is either (a) a syntax error or (b) equivilent to "192.7.34/24". Btw, it appears from my research that the BIND functions *do* impute a "class" if (a) no "/width" is specified and (b) the classful interpretation would be longer than the classless interpretation. No big deal but it qualifies something I said earlier so I thought I'd mention it. > x = 192.7.0.0/16 > ipaddr(x) -> 192.7.0.0 > netmask(x) -> 255.255.0.0 > > These function are defined on the cidr type, and can be called if > someone wants the old output format. Can we wait and see if someone misses / asks for these before we make them? > ..., the 127.1 ambiguity was very strange. netstat -rn is very hard to > understand using the old format. I was amazed at the number of people who had hardwired "127.1" though :-(. > From: Bruce Momjian <maillist@candle.pha.pa.us> > Date: Tue, 21 Jul 1998 01:33:41 -0400 (EDT) > > Doing complex stuff like indexing with contrib stuff is tricky, and one > reason we want to move stuff out of there as it becomes popular. It is > just too hard for someone not experienced with the code to implement. > Add to this the fact that the oid at the time of contrib installation > will change every time you install it, so it is even harder/impossible > to automate. Perhaps we ought to make new type insertion easier since it's so cool? -- Bruce Momjian | http://www.op.net/~candle maillist@candle.pha.pa.us | (610) 853-3000 + If your life is a hard drive, | 830 Blythe Avenue + Christ can be your backup. | Drexel Hill, Pennsylvania 19026
"Marc G. Fournier" <scrappy@hub.org> writes: > *Please* make the appropriate changes and submit a patch...it > should be listed as CIDR, not as IPADDR. MACADDR, IMHO, is okay, as its > the only way I've ever heard of it being referred...but I do not consider > IPADDR to be correct terminology... I agree. I think, though, that the best argument presented in the debate was from Paul Vixie, who wanted INET to be the name covering both IPV4 and IPV6. The following kit makes the needed changes: WARNING! This posting contains two separate patch kits, to be applied at different times, renaming a couple of files in between them! The steps to be taken are marked with "[***]". [***] First apply these patches to change ipaddr to inet. Affected files are: - src/backend/utils/adt/ip.c - src/include/catalog/pg_opclass.h - src/include/catalog/pg_operator.h - src/include/catalog/pg_proc.h - src/include/catalog/pg_type.h - src/include/utils/builtins.h - src/include/utils/mac.h - src/tools/pgindent/pgindent Index: src/backend/utils/adt/ip.c =================================================================== RCS file: /usr/local/cvsroot/pgsql/src/backend/utils/adt/ip.c,v retrieving revision 1.4 diff -r1.4 ip.c 2c2 < * PostgreSQL type definitions for IP addresses. This --- > * PostgreSQL type definitions for the INET type. This 23a24,25 > static int v4bitncmp(unsigned int a1, unsigned int a2, int bits); > 28,29c30,31 < #define ip_addrsize(ipaddrptr) \ < (((ipaddr_struct *)VARDATA(ipaddrptr))->family == AF_INET ? 4 : -1) --- > #define ip_addrsize(inetptr) \ > (((inet_struct *)VARDATA(inetptr))->family == AF_INET ? 4 : -1) 31,32c33,34 < #define ip_family(ipaddrptr) \ < (((ipaddr_struct *)VARDATA(ipaddrptr))->family) --- > #define ip_family(inetptr) \ > (((inet_struct *)VARDATA(inetptr))->family) 34,35c36,37 < #define ip_bits(ipaddrptr) \ < (((ipaddr_struct *)VARDATA(ipaddrptr))->bits) --- > #define ip_bits(inetptr) \ > (((inet_struct *)VARDATA(inetptr))->bits) 37,38c39,40 < #define ip_v4addr(ipaddrptr) \ < (((ipaddr_struct *)VARDATA(ipaddrptr))->addr.ipv4_addr) --- > #define ip_v4addr(inetptr) \ > (((inet_struct *)VARDATA(inetptr))->addr.ipv4_addr) 44,45c46,47 < ipaddr * < ipaddr_in(char *src) --- > inet * > inet_in(char *src) 48c50 < ipaddr *dst; --- > inet *dst; 50c52 < dst = palloc(VARHDRSZ + sizeof(ipaddr_struct)); --- > dst = palloc(VARHDRSZ + sizeof(inet_struct)); 53c55 < elog(ERROR, "unable to allocate memory in ipaddr_in()"); --- > elog(ERROR, "unable to allocate memory in inet_in()"); 78c80 < ipaddr_out(ipaddr *src) --- > inet_out(inet *src) 102c104 < elog(ERROR, "unable to allocate memory in ipaddr_out()"); --- > elog(ERROR, "unable to allocate memory in inet_out()"); 114c116 < ipaddr_lt(ipaddr *a1, ipaddr *a2) --- > inet_lt(inet *a1, inet *a2) 132c134 < ipaddr_le(ipaddr *a1, ipaddr *a2) --- > inet_le(inet *a1, inet *a2) 134c136 < return (ipaddr_lt(a1, a2) || ipaddr_eq(a1, a2)); --- > return (inet_lt(a1, a2) || inet_eq(a1, a2)); 138c140 < ipaddr_eq(ipaddr *a1, ipaddr *a2) --- > inet_eq(inet *a1, inet *a2) 155c157 < ipaddr_ge(ipaddr *a1, ipaddr *a2) --- > inet_ge(inet *a1, inet *a2) 157c159 < return (ipaddr_gt(a1, a2) || ipaddr_eq(a1, a2)); --- > return (inet_gt(a1, a2) || inet_eq(a1, a2)); 161c163 < ipaddr_gt(ipaddr *a1, ipaddr *a2) --- > inet_gt(inet *a1, inet *a2) 179c181 < ipaddr_ne(ipaddr *a1, ipaddr *a2) --- > inet_ne(inet *a1, inet *a2) 181c183 < return (!ipaddr_eq(a1, a2)); --- > return (!inet_eq(a1, a2)); 185c187 < ipaddr_sub(ipaddr *a1, ipaddr *a2) --- > inet_sub(inet *a1, inet *a2) 202c204 < ipaddr_subeq(ipaddr *a1, ipaddr *a2) --- > inet_subeq(inet *a1, inet *a2) 219c221 < ipaddr_sup(ipaddr *a1, ipaddr *a2) --- > inet_sup(inet *a1, inet *a2) 236c238 < ipaddr_supeq(ipaddr *a1, ipaddr *a2) --- > inet_supeq(inet *a1, inet *a2) 257c259 < ipaddr_cmp(ipaddr *a1, ipaddr *a2) --- > inet_cmp(inet *a1, inet *a2) 270c272 < int --- > static int Index: src/include/catalog/pg_opclass.h =================================================================== RCS file: /usr/local/cvsroot/pgsql/src/include/catalog/pg_opclass.h,v retrieving revision 1.12 diff -r1.12 pg_opclass.h 112c112 < DATA(insert OID = 935 ( ipaddr_ops 869 )); --- > DATA(insert OID = 935 ( inet_ops 869 )); Index: src/include/catalog/pg_operator.h =================================================================== RCS file: /usr/local/cvsroot/pgsql/src/include/catalog/pg_operator.h,v retrieving revision 1.39 diff -r1.39 pg_operator.h 647,656c647,656 < DATA(insert OID = 1201 ( "=" PGUID 0 b t t 869 869 16 1201 1202 0 0 ipaddr_eq eqsel eqjoinsel )); < DATA(insert OID = 1202 ( "<>" PGUID 0 b t f 869 869 16 1202 1201 0 0 ipaddr_ne neqsel neqjoinsel )); < DATA(insert OID = 1203 ( "<" PGUID 0 b t f 869 869 16 1205 1206 0 0 ipaddr_lt intltsel intltjoinsel )); < DATA(insert OID = 1204 ( "<=" PGUID 0 b t f 869 869 16 1206 1205 0 0 ipaddr_le intltsel intltjoinsel )); < DATA(insert OID = 1205 ( ">" PGUID 0 b t f 869 869 16 1203 1204 0 0 ipaddr_gt intltsel intltjoinsel )); < DATA(insert OID = 1206 ( ">=" PGUID 0 b t f 869 869 16 1204 1203 0 0 ipaddr_ge intltsel intltjoinsel )); < DATA(insert OID = 931 ( "<<" PGUID 0 b t f 869 869 16 933 934 0 0 ipaddr_sub intltsel intltjoinsel )); < DATA(insert OID = 932 ( "<<=" PGUID 0 b t f 869 869 16 934 933 0 0 ipaddr_subeq intltsel intltjoinsel )); < DATA(insert OID = 933 ( ">>" PGUID 0 b t f 869 869 16 931 932 0 0 ipaddr_sup intltsel intltjoinsel )); < DATA(insert OID = 934 ( ">>=" PGUID 0 b t f 869 869 16 932 931 0 0 ipaddr_supeq intltsel intltjoinsel )); --- > DATA(insert OID = 1201 ( "=" PGUID 0 b t t 869 869 16 1201 1202 0 0 inet_eq eqsel eqjoinsel )); > DATA(insert OID = 1202 ( "<>" PGUID 0 b t f 869 869 16 1202 1201 0 0 inet_ne neqsel neqjoinsel )); > DATA(insert OID = 1203 ( "<" PGUID 0 b t f 869 869 16 1205 1206 0 0 inet_lt intltsel intltjoinsel )); > DATA(insert OID = 1204 ( "<=" PGUID 0 b t f 869 869 16 1206 1205 0 0 inet_le intltsel intltjoinsel )); > DATA(insert OID = 1205 ( ">" PGUID 0 b t f 869 869 16 1203 1204 0 0 inet_gt intltsel intltjoinsel )); > DATA(insert OID = 1206 ( ">=" PGUID 0 b t f 869 869 16 1204 1203 0 0 inet_ge intltsel intltjoinsel )); > DATA(insert OID = 931 ( "<<" PGUID 0 b t f 869 869 16 933 934 0 0 inet_sub intltsel intltjoinsel )); > DATA(insert OID = 932 ( "<<=" PGUID 0 b t f 869 869 16 934 933 0 0 inet_subeq intltsel intltjoinsel )); > DATA(insert OID = 933 ( ">>" PGUID 0 b t f 869 869 16 931 932 0 0 inet_sup intltsel intltjoinsel )); > DATA(insert OID = 934 ( ">>=" PGUID 0 b t f 869 869 16 932 931 0 0 inet_supeq intltsel intltjoinsel )); Index: src/include/catalog/pg_proc.h =================================================================== RCS file: /usr/local/cvsroot/pgsql/src/include/catalog/pg_proc.h,v retrieving revision 1.71 diff -r1.71 pg_proc.h 2072c2072 < DATA(insert OID = 910 ( ipaddr_in PGUID 11 f t f 1 f 869 "0" 100 0 0 100 foo bar )); --- > DATA(insert OID = 910 ( inet_in PGUID 11 f t f 1 f 869 "0" 100 0 0 100 foo bar )); 2074c2074 < DATA(insert OID = 911 ( ipaddr_out PGUID 11 f t f 1 f 23 "0" 100 0 0 100 foo bar )); --- > DATA(insert OID = 911 ( inet_out PGUID 11 f t f 1 f 23 "0" 100 0 0 100 foo bar )); 2077c2077 < DATA(insert OID = 920 ( ipaddr_eq PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100 foo bar )); --- > DATA(insert OID = 920 ( inet_eq PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100 foo bar )); 2079c2079 < DATA(insert OID = 921 ( ipaddr_lt PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100 foo bar )); --- > DATA(insert OID = 921 ( inet_lt PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100 foo bar )); 2081c2081 < DATA(insert OID = 922 ( ipaddr_le PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100 foo bar )); --- > DATA(insert OID = 922 ( inet_le PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100 foo bar )); 2083c2083 < DATA(insert OID = 923 ( ipaddr_gt PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100 foo bar )); --- > DATA(insert OID = 923 ( inet_gt PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100 foo bar )); 2085c2085 < DATA(insert OID = 924 ( ipaddr_ge PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100 foo bar )); --- > DATA(insert OID = 924 ( inet_ge PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100 foo bar )); 2087c2087 < DATA(insert OID = 925 ( ipaddr_ne PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100 foo bar )); --- > DATA(insert OID = 925 ( inet_ne PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100 foo bar )); 2089c2089 < DATA(insert OID = 926 ( ipaddr_cmp PGUID 11 f t f 2 f 23 "869 869" 100 0 0 100 foo bar )); --- > DATA(insert OID = 926 ( inet_cmp PGUID 11 f t f 2 f 23 "869 869" 100 0 0 100 foo bar )); 2091c2091 < DATA(insert OID = 927 ( ipaddr_sub PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100 foo bar )); --- > DATA(insert OID = 927 ( inet_sub PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100 foo bar )); 2093c2093 < DATA(insert OID = 928 ( ipaddr_subeq PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100 foo bar )); --- > DATA(insert OID = 928 ( inet_subeq PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100 foo bar )); 2095c2095 < DATA(insert OID = 929 ( ipaddr_sup PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100 foo bar )); --- > DATA(insert OID = 929 ( inet_sup PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100 foo bar )); 2097c2097 < DATA(insert OID = 930 ( ipaddr_supeq PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100 foo bar )); --- > DATA(insert OID = 930 ( inet_supeq PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100 foo bar )); Index: src/include/catalog/pg_type.h =================================================================== RCS file: /usr/local/cvsroot/pgsql/src/include/catalog/pg_type.h,v retrieving revision 1.48 diff -r1.48 pg_type.h 303c303 < DATA(insert OID = 869 ( ipaddr PGUID -1 -1 f b t \054 0 0 ipaddr_in ipaddr_out ipaddr_in ipaddr_out i _null_ )); --- > DATA(insert OID = 869 ( inet PGUID -1 -1 f b t \054 0 0 inet_in inet_out inet_in inet_out i _null_ )); 342c342 < DATA(insert OID = 1041 ( _ipaddr PGUID -1 -1 f b t \054 0 869 array_in array_out array_in array_out i _null_ )); --- > DATA(insert OID = 1041 ( _inet PGUID -1 -1 f b t \054 0 869 array_in array_out array_in array_out i _null_ )); Index: src/include/utils/builtins.h =================================================================== RCS file: /usr/local/cvsroot/pgsql/src/include/utils/builtins.h,v retrieving revision 1.57 diff -r1.57 builtins.h 522,535c522,534 < ipaddr *ipaddr_in(char *str); < char *ipaddr_out(ipaddr * addr); < bool ipaddr_lt(ipaddr * a1, ipaddr * a2); < bool ipaddr_le(ipaddr * a1, ipaddr * a2); < bool ipaddr_eq(ipaddr * a1, ipaddr * a2); < bool ipaddr_ge(ipaddr * a1, ipaddr * a2); < bool ipaddr_gt(ipaddr * a1, ipaddr * a2); < bool ipaddr_ne(ipaddr * a1, ipaddr * a2); < bool ipaddr_sub(ipaddr * a1, ipaddr * a2); < bool ipaddr_subeq(ipaddr * a1, ipaddr * a2); < bool ipaddr_sup(ipaddr * a1, ipaddr * a2); < bool ipaddr_supeq(ipaddr * a1, ipaddr * a2); < int4 ipaddr_cmp(ipaddr * a1, ipaddr * a2); < int v4bitncmp(unsigned int a1, unsigned int a2, int bits); --- > inet *inet_in(char *str); > char *inet_out(inet * addr); > bool inet_lt(inet * a1, inet * a2); > bool inet_le(inet * a1, inet * a2); > bool inet_eq(inet * a1, inet * a2); > bool inet_ge(inet * a1, inet * a2); > bool inet_gt(inet * a1, inet * a2); > bool inet_ne(inet * a1, inet * a2); > bool inet_sub(inet * a1, inet * a2); > bool inet_subeq(inet * a1, inet * a2); > bool inet_sup(inet * a1, inet * a2); > bool inet_supeq(inet * a1, inet * a2); > int4 inet_cmp(inet * a1, inet * a2); Index: src/include/utils/mac.h =================================================================== RCS file: /usr/local/cvsroot/pgsql/src/include/utils/mac.h,v retrieving revision 1.2 diff -r1.2 mac.h 29c29 < } ipaddr_struct; --- > } inet_struct; 31c31 < typedef struct varlena ipaddr; --- > typedef struct varlena inet; Index: src/tools/pgindent/pgindent =================================================================== RCS file: /usr/local/cvsroot/pgsql/src/tools/pgindent/pgindent,v retrieving revision 1.11 diff -r1.11 pgindent 789c789 < -Tipaddr \ --- > -Tinet \ [***] Then, some renaming is in order: - rename doc/README.ipaddr to doc/README.inet - rename src/backend/utils/adt/ip.c to src/backend/utils/adt/inet.c - rename src/include/utils/mac.h to src/include/utils/network.h [***] Finally, apply these patches to reflect the renaming. Files are: - src/backend/utils/adt/Makefile - src/backend/utils/adt/inet.c - src/backend/utils/adt/mac.c - src/include/utils/builtins.h *** src/backend/utils/adt/Makefile.old Wed Oct 7 10:45:34 1998 --- src/backend/utils/adt/Makefile Wed Oct 7 10:46:38 1998 *************** *** 24,30 **** oid.o oracle_compat.o \ regexp.o regproc.o ruleutils.o selfuncs.o sets.o \ tid.o timestamp.o varchar.o varlena.o version.o \ ! ip.o mac.o inet_net_ntop.o inet_net_pton.o all: SUBSYS.o --- 24,30 ---- oid.o oracle_compat.o \ regexp.o regproc.o ruleutils.o selfuncs.o sets.o \ tid.o timestamp.o varchar.o varlena.o version.o \ ! inet.o mac.o inet_net_ntop.o inet_net_pton.o all: SUBSYS.o *** src/backend/utils/adt/inet.c.old Wed Oct 7 10:45:38 1998 --- src/backend/utils/adt/inet.c Wed Oct 7 10:46:52 1998 *************** *** 19,25 **** #include <postgres.h> #include <utils/palloc.h> #include <utils/builtins.h> ! #include <utils/mac.h> static int v4bitncmp(unsigned int a1, unsigned int a2, int bits); --- 19,25 ---- #include <postgres.h> #include <utils/palloc.h> #include <utils/builtins.h> ! #include <utils/network.h> static int v4bitncmp(unsigned int a1, unsigned int a2, int bits); *** src/backend/utils/adt/mac.c.old Wed Oct 7 10:45:43 1998 --- src/backend/utils/adt/mac.c Wed Oct 7 10:47:11 1998 *************** *** 10,16 **** #include <postgres.h> #include <utils/palloc.h> #include <utils/builtins.h> ! #include <utils/mac.h> manufacturer manufacturers[] = { {0x00, 0x00, 0x0C, "Cisco"}, --- 10,16 ---- #include <postgres.h> #include <utils/palloc.h> #include <utils/builtins.h> ! #include <utils/network.h> manufacturer manufacturers[] = { {0x00, 0x00, 0x0C, "Cisco"}, *** src/include/utils/builtins.h.old Wed Oct 7 10:45:54 1998 --- src/include/utils/builtins.h Wed Oct 7 10:47:28 1998 *************** *** 28,34 **** #include <utils/nabstime.h> #include <utils/int8.h> #include <utils/cash.h> ! #include <utils/mac.h> #include <utils/rel.h> /* --- 28,34 ---- #include <utils/nabstime.h> #include <utils/int8.h> #include <utils/cash.h> ! #include <utils/network.h> #include <utils/rel.h> /* *************** *** 518,524 **** /* inet_net_pton.c */ int inet_net_pton(int af, const char *src, void *dst, size_t size); ! /* ip.c */ inet *inet_in(char *str); char *inet_out(inet * addr); bool inet_lt(inet * a1, inet * a2); --- 518,524 ---- /* inet_net_pton.c */ int inet_net_pton(int af, const char *src, void *dst, size_t size); ! /* inet.c */ inet *inet_in(char *str); char *inet_out(inet * addr); bool inet_lt(inet * a1, inet * a2); [***] Hope that I got it right! "It works for me." :-) -tih -- Popularity is the hallmark of mediocrity. --Niles Crane, "Frasier"
Applied. Thomas, did remove the README.ip, or did you leave it when you decided to merge it into the docs. I still show it here, so I am renaming it. > "Marc G. Fournier" <scrappy@hub.org> writes: > > > *Please* make the appropriate changes and submit a patch...it > > should be listed as CIDR, not as IPADDR. MACADDR, IMHO, is okay, as its > > the only way I've ever heard of it being referred...but I do not consider > > IPADDR to be correct terminology... > > I agree. I think, though, that the best argument presented in the > debate was from Paul Vixie, who wanted INET to be the name covering > both IPV4 and IPV6. The following kit makes the needed changes: > > WARNING! This posting contains two separate patch kits, to be applied > at different times, renaming a couple of files in between them! The > steps to be taken are marked with "[***]". > > [***] First apply these patches to change ipaddr to inet. Affected files are: -- Bruce Momjian | http://www.op.net/~candle maillist@candle.pha.pa.us | (610) 853-3000 + If your life is a hard drive, | 830 Blythe Avenue + Christ can be your backup. | Drexel Hill, Pennsylvania 19026
> Thomas, did remove the README.ip, or did you leave it when you decided > to merge it into the docs. I still show it here, so I am renaming it. I have not yet merged it; it is on my ToDo list for documenting along with the other new datatypes INT8 and SERIAL. We should leave it in the README until I do the merge, just in case... - Tom