1 /* Copyright 2003-2008 Wang, Chun-Pin All rights reserved. */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <sys/socket.h>
5 #include <string.h>
6 #include <syslog.h>
7
8 #include "smbftpd.h"
9
10 typedef struct {
11 union sockunion addr;
12 pid_t pid;
13 } smbftpd_iptable_t;
14
15 static int table_size = 0;
16 static smbftpd_iptable_t *iptable;
17
18 /**
19 * Free the ip table.
20 */
smbftpd_iptrack_free()21 void smbftpd_iptrack_free()
22 {
23 if (iptable) {
24 free(iptable);
25 iptable = NULL;
26 }
27 table_size = 0;
28 }
29
30 /**
31 * Allocate table to record ip address. So we can use
32 * smbftpd_iptrack_add(), smbftpd_iptrack_check(),
33 * smbftpd_iptrack_delete() to control max connection from
34 * the same IP.
35 *
36 * @param maxclient Max client to accept
37 *
38 * @return 0: Success
39 * -1: Failed
40 */
smbftpd_iptrack_alloc(int maxclient)41 int smbftpd_iptrack_alloc(int maxclient)
42 {
43 if (iptable) {
44 smbftpd_iptrack_free();
45 }
46
47 if (!maxclient) {
48 return 0;
49 }
50
51 iptable = calloc(maxclient, sizeof(smbftpd_iptable_t));
52 if (!iptable) {
53 return -1;
54 }
55 table_size = maxclient;
56
57 return 0;
58 }
59
60 /**
61 * Add an IP/pid into iptable
62 *
63 * @param addr The client's ip address
64 * @param pid The process id of the fork()ed process
65 */
smbftpd_iptrack_add(union sockunion * addr,pid_t pid)66 void smbftpd_iptrack_add(union sockunion *addr, pid_t pid)
67 {
68 int i = 0;
69
70 if (!iptable) {
71 return;
72 }
73
74 do {
75 if (iptable[i].pid == 0) {
76 iptable[i].addr = *addr;
77 iptable[i].pid = pid;
78 return;
79 }
80 i++;
81 } while ( i < table_size );
82
83 // Table full, Remove the first item. Should never happen?
84 memmove(&(iptable[0]), &(iptable[1]), sizeof(iptable[0]) * (table_size - 1));
85 iptable[table_size-1].addr = *addr;
86 iptable[table_size-1].pid = pid;
87
88 return;
89 }
90
91 /**
92 * Check whether the max connection from the same ip
93 * has reached limit
94 *
95 * @param maxip Max connection per ip.
96 * @param addr The client's IP
97 *
98 * @return 0: Allowed
99 * -1: Exceed the limit
100 */
smbftpd_iptrack_check(int maxip,union sockunion * addr)101 int smbftpd_iptrack_check(int maxip, union sockunion *addr)
102 {
103 int i = 0;
104 int match = 0;
105
106 if (!iptable || !maxip || !addr) {
107 return 0;
108 }
109
110 do {
111 if (iptable[i].pid != 0 && iptable[i].addr.su_family == addr->su_family) {
112 if (iptable[i].addr.su_family == AF_INET &&
113 iptable[i].addr.su_sin.sin_addr.s_addr == addr->su_sin.sin_addr.s_addr) {
114 match++;
115 #ifdef INET6
116 } else if (iptable[i].addr.su_family == AF_INET6 &&
117 IN6_ARE_ADDR_EQUAL(&iptable[i].addr.su_sin6.sin6_addr, &addr->su_sin6.sin6_addr)) {
118 match++;
119 #endif
120 }
121 }
122 i++;
123 } while ( i < table_size );
124
125 if (match >= maxip) {
126 return -1;
127 }
128
129 return 0;
130 }
131
132 /**
133 * Remove the pid/ip from iptable.
134 *
135 * This function is called when client disconnects
136 *
137 * @param pid The process id of fork()ed process
138 */
smbftpd_iptrack_delete(pid_t pid)139 void smbftpd_iptrack_delete(pid_t pid)
140 {
141 int i = 0;
142
143 if (!iptable) {
144 return;
145 }
146
147 do {
148 if (iptable[i].pid == pid) {
149 iptable[i].pid = 0;
150 return;
151 }
152 i++;
153 } while ( i < table_size );
154 }
155
156