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