perl -i -npe "s/[ \t]+$//g" `find src -name "*.[ch]" -print`
[freeradius.git] / src / modules / rlm_ippool / rlm_ippool_tool.c
1 /*
2  * rlm_ippool_tool.c
3  *
4  * Version:  $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * Copyright 2003  FreeRADIUS Project, http://www.freeradius.org/
21  * Copyright 2003  Edwin Groothuis, edwin@mavetju.org
22  * Permission from Edwin Groothuis for release under GPL is archived here:
23  * http://lists.cistron.nl/archives/freeradius-devel/2003/09/frm00247.html
24  *
25  */
26
27 // The original license follows. This license applies to the tarball at
28 // http://www.mavetju.org/unix/general.php
29
30 // Copyright 2003 by Edwin Groothuis, edwin@mavetju.org
31 // All rights reserved.
32 //
33 // Redistribution and use in source and binary forms, with or without
34 // modification, are permitted provided that the following conditions
35 // are met:
36 // 1. Redistributions of source code must retain the above copyright
37 //    notice, this list of conditions and the following disclaimer.
38 // 2. Redistributions in binary form must reproduce the above copyright
39 //    notice, this list of conditions and the following disclaimer in the
40 //    documentation and/or other materials provided with the distribution.
41 //
42 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
43 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 // ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
46 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 // SUCH DAMAGE.
53
54 #include <sys/types.h>
55 #include <sys/socket.h>
56 #include <netinet/in.h>
57 #include <arpa/inet.h>
58 #include <stdio.h>
59 #include <fcntl.h>
60 #include <gdbm.h>
61 #include <unistd.h>
62 #include <stdlib.h>
63 #include <string.h>
64
65 int active=0;
66
67 int aflag=0;
68 int cflag=0;
69 int rflag=0;
70 int vflag=0;
71 int nflag=0;
72
73 typedef struct ippool_info {
74     uint32_t        ipaddr;
75     char            active;
76     char            cli[32];
77         char                    extra;
78 } ippool_info;
79
80
81 #define MAX_NAS_NAME_SIZE 64
82 typedef struct ippool_key {
83     char nas[MAX_NAS_NAME_SIZE];
84     unsigned int port;
85 } ippool_key;
86
87 #define MATCH_IP(ip1,ip2) ((ip1)==NULL || strcmp((ip1),(ip2))==0)
88 #define MATCH_ACTIVE(info) ((info).active==1 || !aflag)
89
90 void addip(char *sessiondbname,char *indexdbname,char *ipaddress, char* NASname, char*NASport);
91 void viewdb(char *sessiondbname,char *indexdbname,char *ipaddress);
92 void usage(char *argv0);
93
94 void addip(char *sessiondbname,char *indexdbname,char *ipaddress, char* NASname, char*NASport) {
95     GDBM_FILE sessiondb;
96     GDBM_FILE indexdb;
97     datum key_datum,data_datum,save_datum;
98         datum nextkey;
99     ippool_key key;
100     ippool_info entry;
101     struct in_addr ipaddr;
102     int num=0;
103         int mppp=0;
104     int mode=GDBM_WRITER;
105     signed int rcode;
106         char *cli = NULL;
107         int delete = 0;
108         int port;
109         int extra = 0;
110         int found = 0;
111
112     sessiondb=gdbm_open(sessiondbname,512,mode,0,NULL);
113     indexdb=gdbm_open(indexdbname,512,mode,0,NULL);
114
115         if (inet_aton(ipaddress, &ipaddr) == 0)
116         {
117                 printf("rlm_ippool_tool: Unable to convert IP address '%s'\n", ipaddress);
118                 return;
119         }
120
121     if (sessiondb==NULL)
122         {
123                 printf("rlm_ippool_tool: Unable to open DB '%s'\n", sessiondbname);
124                 return;
125         }
126
127     if (indexdb==NULL)
128         {
129                 printf("rlm_ippool_tool: Unable to open DB '%s'\n", indexdbname);
130                 return;
131         }
132
133         port = strtoul(NASport,NULL,0);
134
135         /* Basically from rlm_ippool.c */
136
137         memset(key.nas,0,MAX_NAS_NAME_SIZE);
138         strncpy(key.nas,NASname,MAX_NAS_NAME_SIZE -1 );
139         key.port = port;
140         key_datum.dptr = (char *) &key;
141         key_datum.dsize = sizeof(ippool_key);
142
143         data_datum = gdbm_fetch(sessiondb, key_datum);
144         if (data_datum.dptr != NULL){
145                 found = 1;
146                 memcpy(&entry,data_datum.dptr, sizeof(ippool_info));
147                 free(data_datum.dptr);
148                 if (entry.active){
149                         printf("rlm_ippool_tool: Deleting stale entry for ip/port %s/%u",
150                                         ipaddress, port);
151                         entry.active = 0;
152                         save_datum.dptr = key_datum.dptr;
153                         save_datum.dsize = key_datum.dsize;
154
155                         data_datum.dptr = (char*) &entry;
156                         data_datum.dsize = sizeof(ippool_info);
157
158                         rcode = gdbm_store(sessiondb, key_datum, data_datum, GDBM_REPLACE);
159                         if (rcode < 0) {
160                                 printf("rlm_ippool_tool: Failed storing data to %s: %s\n",
161                                         sessiondbname, gdbm_strerror(gdbm_errno));
162                                 gdbm_close(indexdb);
163                                 gdbm_close(sessiondb);
164                                 return;
165                         }
166
167                         key_datum.dptr = (char *) &entry.ipaddr;
168                         key_datum.dsize = sizeof(uint32_t);
169                         data_datum = gdbm_fetch(indexdb, key_datum);
170                         if (data_datum.dptr != NULL) {
171                                 memcpy(&num, data_datum.dptr, sizeof(int));
172                                 free(data_datum.dptr);
173                                 if (num > 0) {
174                                         num--;
175                                         data_datum.dptr = (char *) &num;
176                                         data_datum.dsize = sizeof(int);
177                                         rcode = gdbm_store(indexdb, key_datum, data_datum, GDBM_REPLACE);
178                                         if (rcode < 0) {
179                                                 printf("rlm_ippool_tool: Failed storing data to %s: %s\n",
180                                                         indexdbname, gdbm_strerror(gdbm_errno));
181                                                 gdbm_close(indexdb);
182                                                 gdbm_close(sessiondb);
183                                                 return;
184                                         }
185                                         if (num > 0 && entry.extra == 1) {
186                                                 gdbm_delete(sessiondb, save_datum);
187                                         }
188                                 }
189                         }
190                 }
191         }
192         key_datum.dptr = NULL;
193
194         if (cli != NULL){
195                 key_datum = gdbm_firstkey(sessiondb);
196                 while(key_datum.dptr){
197                         data_datum = gdbm_fetch(sessiondb, key_datum);
198                         if (data_datum.dptr){
199                                 memcpy(&entry,data_datum.dptr, sizeof(ippool_info));
200                                 free(data_datum.dptr);
201                                 /*
202                                 * If we find an entry for the same caller-id and nas with active=1
203                                 * then we use that for multilink (MPPP) to work properly.
204                                 */
205                                 if (strcmp(entry.cli,cli) == 0 && entry.active){
206                                         memcpy(&key,key_datum.dptr,sizeof(ippool_key));
207                                         if (!strcmp(key.nas,NASname)){
208                                                 mppp = 1;
209                                                 break;
210                                         }
211                                 }
212                         }
213                         nextkey = gdbm_nextkey(sessiondb, key_datum);
214                         free(key_datum.dptr);
215                         key_datum = nextkey;
216                 }
217         }
218
219         if (key_datum.dptr == NULL) {
220                 key_datum = gdbm_firstkey(sessiondb);
221                 while (key_datum.dptr) {
222                         data_datum = gdbm_fetch(sessiondb, key_datum);
223                         if (data_datum.dptr != NULL) {
224                                 memcpy(&entry, data_datum.dptr, sizeof(ippool_info));
225                                 free(data_datum.dptr);
226
227                                 if (entry.active == 0 && entry.ipaddr == ipaddr.s_addr) {
228                                         datum tmp;
229                                         tmp.dptr = (char *) &entry.ipaddr;
230                                         tmp.dsize = sizeof(uint32_t);
231                                         data_datum = gdbm_fetch(indexdb, tmp);
232                                         if (data_datum.dptr){
233                                                 memcpy(&num, data_datum.dptr, sizeof(int));
234                                                 free(data_datum.dptr);
235                                                 if (num == 0){
236                                                         delete = 1;
237                                                         break;
238                                                 }
239                                         } else {
240                                                 delete = 1;
241                                                 break;
242                                         }
243                                 }
244                         }
245                         nextkey = gdbm_nextkey(sessiondb, key_datum);
246                         free(key_datum.dptr);
247                         key_datum = nextkey;
248                 }
249         }
250
251         if (key_datum.dptr){
252                 if (found && ! mppp){
253                         datum key_datum_tmp,data_datum_tmp;
254                         ippool_key key_tmp;
255                         memset(key_tmp.nas,0,MAX_NAS_NAME_SIZE);
256                         strncpy(key_tmp.nas,NASname,MAX_NAS_NAME_SIZE - 1);
257                         key_tmp.port=port;
258                         key_datum_tmp.dptr = (char *) &key_tmp;
259                         key_datum_tmp.dsize = sizeof(ippool_key);
260
261                         data_datum_tmp = gdbm_fetch(sessiondb, key_datum_tmp);
262                         if (data_datum_tmp.dptr != NULL) {
263                                 rcode = gdbm_store(sessiondb, key_datum, data_datum_tmp, GDBM_REPLACE);
264                                 if (rcode < 0) {
265                                         printf("rlm_ippool_tool: Failed storing data to %s: %s\n",
266                                                 sessiondbname, gdbm_strerror(gdbm_errno));
267                                                 gdbm_close(indexdb);
268                                                 gdbm_close(sessiondb);
269                                         return;
270                                 }
271                                 free(data_datum_tmp.dptr);
272                         }
273                 } else {
274                         if (delete)
275                                 gdbm_delete(sessiondb, key_datum);
276                         else {
277                                 if (mppp)
278                                         extra = 1;
279 //                              if (!mppp)
280 //                                      printf("Error in if statements!!!\n");
281                         }
282                 }
283                 free(key_datum.dptr);
284                 entry.active=1;
285                 if (extra)
286                         entry.extra=1;
287                 data_datum.dptr = (char *) &entry;
288                 data_datum.dsize = sizeof(ippool_info);
289                 memset(key.nas,0,MAX_NAS_NAME_SIZE);
290                 strncpy(key.nas,NASname,MAX_NAS_NAME_SIZE -1 );
291                 key.port = port;
292                 key_datum.dptr = (char *) &key;
293                 key_datum.dsize = sizeof(ippool_key);
294                 printf("rlm_ippool_tool: Allocating ip to nas/port: %s/%u\n",key.nas,key.port);
295                 rcode = gdbm_store(sessiondb, key_datum, data_datum, GDBM_REPLACE);
296                 if (rcode < 0) {
297                         printf("rlm_ippool_tool: Failed storing data to %s: %s\n",
298                                 sessiondbname, gdbm_strerror(gdbm_errno));
299                         gdbm_close(indexdb);
300                         gdbm_close(sessiondb);
301                         return;
302                 }
303
304                 /* Increase the ip index count */
305                 key_datum.dptr = (char *) &entry.ipaddr;
306                 key_datum.dsize = sizeof(uint32_t);
307                 data_datum = gdbm_fetch(indexdb, key_datum);
308                 if (data_datum.dptr){
309                         memcpy(&num,data_datum.dptr,sizeof(int));
310                         free(data_datum.dptr);
311                 } else
312                         num = 0;
313                 num++;
314                 printf("rlm_ippool_tool: num: %d\n",num);
315                 data_datum.dptr = (char *) &num;
316                 data_datum.dsize = sizeof(int);
317                 rcode = gdbm_store(indexdb, key_datum, data_datum, GDBM_REPLACE);
318                 if (rcode < 0) {
319                         printf("rlm_ippool_tool: Failed storing data to %s: %s\n",
320                                 indexdbname, gdbm_strerror(gdbm_errno));
321                         gdbm_close(indexdb);
322                         gdbm_close(sessiondb);
323                         return;
324                 }
325
326                 printf("rlm_ippool_tool: Allocated ip %s to client on nas %s,port %u\n",
327                                 ipaddress, key.nas,port);
328
329         }
330     gdbm_close(indexdb);
331     gdbm_close(sessiondb);
332 }
333
334 void viewdb(char *sessiondbname,char *indexdbname,char *ipaddress) {
335     GDBM_FILE sessiondb;
336     GDBM_FILE indexdb;
337     datum key_datum,keynext_datum,data_datum,save_datum;
338     ippool_key key;
339     ippool_info info;
340     struct in_addr ipaddr;
341     int num;
342     char *ip;
343     int mode=GDBM_READER;
344     int rcode;
345
346     if (rflag) mode=GDBM_WRITER;
347     sessiondb=gdbm_open(sessiondbname,512,mode,0,NULL);
348     indexdb=gdbm_open(indexdbname,512,mode,0,NULL);
349
350     if (sessiondb==NULL || indexdb==NULL) return;
351
352     key_datum=gdbm_firstkey(sessiondb);
353     while (key_datum.dptr) {
354         keynext_datum=gdbm_nextkey(sessiondb,key_datum);
355         if (key_datum.dsize==sizeof(struct ippool_key)) {
356             memcpy(&key,key_datum.dptr,sizeof(struct ippool_key));
357
358             data_datum=gdbm_fetch(sessiondb,key_datum);
359             if (data_datum.dptr!=NULL) {
360
361                 memcpy(&info,data_datum.dptr,sizeof(struct ippool_info));
362                 memcpy(&ipaddr,&info.ipaddr,4);
363                 ip=inet_ntoa(ipaddr);
364
365                 if (info.active) active++;
366                 if (vflag && MATCH_IP(ipaddress,ip) && MATCH_ACTIVE(info))
367                     printf("NAS:%s port:0x%x - ",key.nas,key.port);
368                 if (!vflag && aflag && info.active && MATCH_IP(ipaddress,ip))
369                     printf("%s\n",ip);
370                 else if (vflag && MATCH_IP(ipaddress,ip) && MATCH_ACTIVE(info))
371                     printf("ipaddr:%s active:%d cli:%s",
372                         inet_ntoa(ipaddr),info.active,info.cli);
373
374                 //
375                 // algorythm copied from rlm_ippool.c:
376                 // - set active to zero
377                 // - set number of sessions to zero
378                 //
379                 if (rflag && MATCH_IP(ipaddress,ip)) {
380                     info.active=0;
381                         save_datum.dptr = key_datum.dptr;
382                         save_datum.dsize = key_datum.dsize;
383                     data_datum.dptr = (char *) &info;
384                     data_datum.dsize = sizeof(ippool_info);
385                     rcode=gdbm_store(sessiondb,key_datum,data_datum,GDBM_REPLACE);
386                     if (rcode < 0) {
387                                 printf("Failed to update %s: %s\n",ip,gdbm_strerror(gdbm_errno));
388                                 gdbm_close(indexdb);
389                                 gdbm_close(sessiondb);
390                                 return;
391                         }
392                     key_datum.dptr=(char *)&info.ipaddr;
393                     key_datum.dsize = sizeof(uint32_t);
394                     data_datum=gdbm_fetch(indexdb,key_datum);
395                     if (data_datum.dptr!=NULL) {
396                                 memcpy(&num, data_datum.dptr, sizeof(int));
397                                 if (num>0) {
398                                         num--;
399                                         data_datum.dptr = (char *) &num;
400                                         data_datum.dsize = sizeof(int);
401                                         rcode = gdbm_store(indexdb, key_datum, data_datum, GDBM_REPLACE);
402                                         if (rcode < 0) {
403                                                 printf("Failed to update %s: %s\n",ip,gdbm_strerror(gdbm_errno));
404                                                 gdbm_close(indexdb);
405                                                 gdbm_close(sessiondb);
406                                                 return;
407                                         }
408                                         if (num > 0 && info.extra == 1) {
409                                                 gdbm_delete(sessiondb, save_datum);
410                                         }
411                                 }
412                     }
413                 }
414
415                 key_datum.dptr=(char *)&info.ipaddr;
416                 key_datum.dsize = sizeof(uint32_t);
417                 data_datum=gdbm_fetch(indexdb,key_datum);
418                 if (data_datum.dptr!=NULL) {
419                     memcpy(&num, data_datum.dptr, sizeof(int));
420                     if (vflag && MATCH_IP(ipaddress,ip) && MATCH_ACTIVE(info))
421                         printf(" num:%d",num);
422                 }
423                 if (vflag && MATCH_IP(ipaddress,ip) && MATCH_ACTIVE(info))
424                     printf("\n");
425             } else
426                 if (vflag && ipaddress==NULL)
427                     printf("NAS:%s port:0x%x\n",key.nas,key.port);
428         }
429         key_datum=keynext_datum;
430     }
431     gdbm_close(indexdb);
432     gdbm_close(sessiondb);
433 }
434
435 void usage(char *argv0) {
436     printf("Usage: %s [-a] [-c] [-v] <session-db> <index-db> [ipaddress]\n",argv0);
437     printf("-a: print all active entries\n");
438     printf("-c: report number of active entries\n");
439     printf("-r: remove active entries\n");
440     printf("-v: verbose report of all entries\n");
441     printf("If an ipaddress is specified then that address is used to\n");
442     printf("limit the actions or output.\n");
443     printf("Usage: %s -n  <session-db> <index-db> <ipaddress> <nasIP> <nasPort>\n",argv0);
444     printf("-n: Mark the entry nasIP/nasPort as having ipaddress\n");
445     exit(0);
446 }
447
448 int main(int argc,char **argv) {
449     int ch;
450     char *argv0=argv[0];
451
452     while ((ch=getopt(argc,argv,"acrvn"))!=-1)
453         switch (ch) {
454         case 'a': aflag++;break;
455         case 'c': cflag++;break;
456         case 'r': rflag++;break;
457         case 'v': vflag=1;break;
458         case 'n': nflag=1;break;
459         default: usage(argv0);
460         }
461     argc -= optind;
462     argv += optind;
463
464     if ((argc==2 || argc==3) && !nflag) {
465                 viewdb(argv[0],argv[1],argv[2]);
466                 if (cflag) printf("%d\n",active);
467         } else
468                 if (argc==5 && nflag)
469                         addip(argv[0],argv[1],argv[2],argv[3],argv[4]);
470                 else
471                         usage(argv0);
472     return 0;
473 }