Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit674b22a

Browse files
committed
From: Tom I Helbekkmo <tih@Hamartun.Priv.NO>
PostgreSQL type extensions for IP and MAC addresses.I needed to record IP and MAC level ethernet addresses in a database, and I really didn't want to store them as plain strings, withno enforced error checking, so I put together the accompanying codeas my first experiment with adding a data type to PostgreSQL. Ithen thought that this might be useful to others, both directly andas a very simple example of how to do this sort of thing, so hereit is, in the hope that it will be useful.
1 parent9f8d3b6 commit674b22a

File tree

7 files changed

+834
-0
lines changed

7 files changed

+834
-0
lines changed

‎contrib/ip_and_mac/Makefile

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#PostgreSQL type definitions for IP and MAC addresses.
2+
3+
all: ip.so mac.so
4+
5+
ip.so: ip.o
6+
ld -Bshareable -o ip.so ip.o
7+
8+
ip.o: ip.c
9+
cc -g -O -fPIC -I/usr/local/pgsql/include -c ip.c
10+
11+
mac.so: mac.o
12+
ld -Bshareable -o mac.so mac.o
13+
14+
mac.o: mac.c mac.h
15+
cc -g -O -fPIC -I/usr/local/pgsql/include -c mac.c
16+
17+
install: ip.so mac.so
18+
install -c ip.so mac.so /usr/local/pgsql/modules
19+
20+
#eof

‎contrib/ip_and_mac/README

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
PostgreSQL type extensions for IP and MAC addresses.
2+
---------------------------------------------------
3+
4+
I needed to record IP and MAC level ethernet addresses in a data
5+
base, and I really didn't want to store them as plain strings, with
6+
no enforced error checking, so I put together the accompanying code
7+
as my first experiment with adding a data type to PostgreSQL. I
8+
then thought that this might be useful to others, both directly and
9+
as a very simple example of how to do this sort of thing, so here
10+
it is, in the hope that it will be useful.
11+
12+
IP addresses are implemented as an 8 byte struct (this may well be
13+
more than is useful, but I figured that since it has to be at least 5,
14+
it might as well round well) that contains the four bytes of address
15+
and a mask width. Thus, a node address looks like '158.37.96.15/32'
16+
(or just '158.37.96.15', which is understood to mean the same thing).
17+
This address happens to be part of a subnet where I work;
18+
'158.37.96.0/24', which itself is a part of the larger subnet
19+
allocated to our institution, which is '158.37.96.0/21', which again,
20+
if you go by the book, is part of the class "B" net '158.37.0.0/16'.
21+
22+
Input and output functions are supplied, along with the "normal" <,
23+
<=, =, >=, > and <> operators, which all do what you expect, and the
24+
similarity operator ~~, which checks whether two given addresses are
25+
either the same, or, failing that, whether one is a subnet
26+
specification and the other an address (or a smaller subnet) within
27+
that. Good for picking out records with addresses in a given subnet:
28+
note that '158.37.96.0/21' spans '158.37.96.0' to '158.37.103.255',
29+
which is not all that easily handled in its external representation.
30+
31+
MAC level ethernet addresses are also implemented as an 8 byte struct
32+
(I wish I knew what alignment needs are actually present -- I'm just
33+
not taking any chances here) that contains the address as unsigned
34+
chars. Several input forms are accepted: the following are all the
35+
same address: '08002b:010203', '08002b-010203', '0800.2b01.0203',
36+
'08-00-2b-01-02-03' and '08:00:2b:01:02:03'. Upper and lower case is
37+
accepted for the digits 'a' through 'f'. Output is always in the
38+
latter of the given forms.
39+
40+
Input and output functions are supplied, along with the = and <>
41+
operators, which do what you expect, and the similarity operator ~~,
42+
which checks whether two given addresses belong to hardware from the
43+
same manufacturer (first three bytes the same, that is). As an extra
44+
feature, a function macaddr_manuf() is defined, which returns the name
45+
of the manufacturer as a string.
46+
47+
To install: fix the path names in the SQL files and the Makefile if
48+
you need to, then make, make install, slurp the SQL files into psql or
49+
whatever, and you're off. Enjoy!
50+
51+
Bergen, Norway, 1998-01-11, Tom Ivar Helbekkmo (tih@Hamartun.Priv.NO).

‎contrib/ip_and_mac/ip.c

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
/*
2+
*PostgreSQL type definitions for IP addresses.
3+
*/
4+
5+
#include<stdio.h>
6+
7+
#include<postgres.h>
8+
#include<utils/palloc.h>
9+
10+
/*
11+
*This is the internal storage format for IP addresses:
12+
*/
13+
14+
typedefstructipaddr {
15+
unsignedchara;
16+
unsignedcharb;
17+
unsignedcharc;
18+
unsignedchard;
19+
unsignedcharw;
20+
unsignedcharpad1;
21+
shortpad2;
22+
}ipaddr;
23+
24+
/*
25+
*Various forward declarations:
26+
*/
27+
28+
ipaddr*ipaddr_in(char*str);
29+
char*ipaddr_out(ipaddr*addr);
30+
31+
boolipaddr_lt(ipaddr*a1,ipaddr*a2);
32+
boolipaddr_le(ipaddr*a1,ipaddr*a2);
33+
boolipaddr_eq(ipaddr*a1,ipaddr*a2);
34+
boolipaddr_ge(ipaddr*a1,ipaddr*a2);
35+
boolipaddr_gt(ipaddr*a1,ipaddr*a2);
36+
37+
boolipaddr_ne(ipaddr*a1,ipaddr*a2);
38+
int4ipaddr_cmp(ipaddr*a1,ipaddr*a2);
39+
boolipaddr_like(ipaddr*a1,ipaddr*a2);
40+
41+
/*
42+
*A utility macro used for sorting addresses numerically:
43+
*/
44+
45+
#defineMag(addr) \
46+
((unsigned long)((addr->a<<24)|(addr->b<<16)|(addr->c<<8)|(addr->d)))
47+
48+
/*
49+
*IP address reader. Note how the count returned by sscanf()
50+
*is used to determine whether the mask size was specified.
51+
*/
52+
53+
ipaddr*ipaddr_in(char*str) {
54+
inta,b,c,d,w;
55+
ipaddr*result;
56+
intcount;
57+
58+
if (strlen(str)>0) {
59+
60+
count=sscanf(str,"%d.%d.%d.%d/%d",&a,&b,&c,&d,&w);
61+
62+
if (count<4) {
63+
elog(ERROR,"ipaddr_in: error in parsing \"%s\"",str);
64+
return(NULL);
65+
}
66+
67+
if (count==4)
68+
w=32;
69+
70+
if ((a<0)|| (a>255)|| (b<0)|| (b>255)||
71+
(c<0)|| (c>255)|| (d<0)|| (d>255)||
72+
(w<0)|| (w>32)) {
73+
elog(ERROR,"ipaddr_in: illegal address \"%s\"",str);
74+
return(NULL);
75+
}
76+
}else {
77+
a=b=c=d=w=0;/* special case for missing address */
78+
}
79+
80+
result= (ipaddr*)palloc(sizeof(ipaddr));
81+
82+
result->a=a;
83+
result->b=b;
84+
result->c=c;
85+
result->d=d;
86+
result->w=w;
87+
88+
return(result);
89+
}
90+
91+
/*
92+
*IP address output function. Note mask size specification
93+
*generated only for subnets, not for plain host addresses.
94+
*/
95+
96+
char*ipaddr_out(ipaddr*addr) {
97+
char*result;
98+
99+
if (addr==NULL)
100+
return(NULL);
101+
102+
result= (char*)palloc(32);
103+
104+
if (Mag(addr)>0) {
105+
if (addr->w==32)
106+
sprintf(result,"%d.%d.%d.%d",
107+
addr->a,addr->b,addr->c,addr->d);
108+
else
109+
sprintf(result,"%d.%d.%d.%d/%d",
110+
addr->a,addr->b,addr->c,addr->d,addr->w);
111+
}else {
112+
result[0]=0;/* special case for missing address */
113+
}
114+
return(result);
115+
}
116+
117+
/*
118+
*Boolean tests. The Mag() macro was defined above.
119+
*/
120+
121+
boolipaddr_lt(ipaddr*a1,ipaddr*a2) {
122+
unsigned longa1mag,a2mag;
123+
a1mag=Mag(a1);
124+
a2mag=Mag(a2);
125+
return (a1mag<a2mag);
126+
};
127+
128+
boolipaddr_le(ipaddr*a1,ipaddr*a2) {
129+
unsigned longa1mag,a2mag;
130+
a1mag=Mag(a1);
131+
a2mag=Mag(a2);
132+
return (a1mag <=a2mag);
133+
};
134+
135+
boolipaddr_eq(ipaddr*a1,ipaddr*a2) {
136+
unsigned longa1mag,a2mag;
137+
a1mag=Mag(a1);
138+
a2mag=Mag(a2);
139+
return ((a1mag==a2mag)&& (a1->w==a2->w));
140+
};
141+
142+
boolipaddr_ge(ipaddr*a1,ipaddr*a2) {
143+
unsigned longa1mag,a2mag;
144+
a1mag=Mag(a1);
145+
a2mag=Mag(a2);
146+
return (a1mag >=a2mag);
147+
};
148+
149+
boolipaddr_gt(ipaddr*a1,ipaddr*a2) {
150+
unsigned longa1mag,a2mag;
151+
a1mag=Mag(a1);
152+
a2mag=Mag(a2);
153+
return (a1mag>a2mag);
154+
};
155+
156+
boolipaddr_ne(ipaddr*a1,ipaddr*a2) {
157+
unsigned longa1mag,a2mag;
158+
a1mag=Mag(a1);
159+
a2mag=Mag(a2);
160+
return ((a1mag!=a2mag)|| (a1->w!=a2->w));
161+
};
162+
163+
/*
164+
*Comparison function for sorting:
165+
*/
166+
167+
int4ipaddr_cmp(ipaddr*a1,ipaddr*a2) {
168+
unsigned longa1mag=Mag(a1),a2mag=Mag(a2);
169+
if (a1mag<a2mag)
170+
return-1;
171+
elseif (a1mag>a2mag)
172+
return1;
173+
else
174+
return0;
175+
}
176+
177+
/*
178+
*Our "similarity" operator checks whether two addresses are
179+
*either the same node address, or, failing that, whether one
180+
*of them contains the other. This will be true if they have
181+
*the same high bits down as far as the shortest mask reaches.
182+
*/
183+
184+
unsigned longbuild_mask(unsignedcharbits) {
185+
unsigned longmask=0;
186+
inti;
187+
for (i=0;i<bits;i++)
188+
mask= (mask >>1) |0x80000000;
189+
returnmask;
190+
}
191+
192+
boolipaddr_like(ipaddr*a1,ipaddr*a2) {
193+
unsigned longa1bits,a2bits,maskbits;
194+
if ((a1->w==0)|| (a2->w==0))
195+
return FALSE;
196+
if ((a1->w==32)&& (a2->w==32))
197+
returnipaddr_eq(a1,a2);
198+
a1bits=Mag(a1);
199+
a2bits=Mag(a2);
200+
if (a1->w>a2->w) {
201+
maskbits=build_mask(a2->w);
202+
return ((a1bits&maskbits)== (a2bits&maskbits));
203+
}else {
204+
maskbits=build_mask(a1->w);
205+
return ((a2bits&maskbits)== (a1bits&maskbits));
206+
}
207+
return FALSE;
208+
}
209+
210+
/*
211+
*eof
212+
*/

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp