IPTables.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. #include "IPTables.h"
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include "Debug.h"
  6. #include "IPAddress.h"
  7. const char *IPTables::IPSetName()
  8. {
  9. return "evil_hackers";
  10. }
  11. // Ban a list of IPs using ipset and restore.
  12. // Set shouldAdd to true to add to ipset.
  13. // Set shouldAdd to false to remove from ipset.
  14. void IPTables::BanIPsUsingRestore(std::forward_list<IPAddress*> &ipsToAddFast,bool shouldAdd)
  15. {
  16. FILE *fOutput;
  17. const char *command = "sudo ipset restore";
  18. const int BUFFER_SIZE = 1024;
  19. char buffer[BUFFER_SIZE];
  20. const char *ipsetName;
  21. DEBUG;
  22. ipsetName = IPSetName();
  23. fOutput = popen(command,"w");
  24. if (fOutput == NULL) {
  25. throw "Error running command ipset restore";
  26. }
  27. for(auto loop = ipsToAddFast.begin();loop != ipsToAddFast.end();++loop) {
  28. if (shouldAdd) {
  29. snprintf(buffer,BUFFER_SIZE,"add %s %s\n",ipsetName,(*loop)->IP);
  30. fputs(buffer,fOutput);
  31. printf("Added %s\n",(*loop)->IP);
  32. } else {
  33. snprintf(buffer,BUFFER_SIZE,"del %s %s\n",ipsetName,(*loop)->IP);
  34. fputs(buffer,fOutput);
  35. printf("Removed %s\n",(*loop)->IP);
  36. }
  37. }
  38. pclose(fOutput);
  39. DEBUG;
  40. }
  41. // Create the ipset name. The program must already know it doesn't exist before calling.
  42. void IPTables::CreateIpsetSetname()
  43. {
  44. const int BUFFER_SIZE = 200;
  45. char buffer[BUFFER_SIZE];
  46. snprintf(buffer,BUFFER_SIZE,"sudo ipset create %s iphash",IPTables::IPSetName());
  47. printf("%s\n",buffer);
  48. system(buffer);
  49. return;
  50. }
  51. // Make sure iptables has the right ban rule for ipset.
  52. void IPTables::MakeSureIptablesHasIpsetRule()
  53. {
  54. const int BUFFER_SIZE = 200;
  55. char buffer[BUFFER_SIZE];
  56. bool hasIpsetRule;
  57. Tree<IPAddress> ipList;
  58. const char *ipSetName;
  59. // Look for rule in iptables.
  60. ipSetName = IPTables::IPSetName();
  61. ReadFromIptables(ipList,false,true);
  62. hasIpsetRule = false;
  63. for(auto loop = ipList.List.begin();loop != ipList.List.end();++loop) {
  64. if (strcasestr((*loop)->IP,ipSetName)!=nullptr) {
  65. hasIpsetRule = true;
  66. break;
  67. }
  68. }
  69. ipList.Clear();
  70. if (!hasIpsetRule) {
  71. snprintf(buffer,BUFFER_SIZE,"sudo iptables -A INPUT -m set --match-set %s src -j DROP",ipSetName);
  72. printf("%s\n",buffer);
  73. system(buffer);
  74. }
  75. }
  76. // Ban this IP using ipset or iptables.
  77. void IPTables::BanThisIP(IPAddress &ip,bool useIpset)
  78. {
  79. const int COMMAND_SIZE = 200;
  80. char command[COMMAND_SIZE];
  81. if (useIpset) {
  82. snprintf(command,COMMAND_SIZE,"sudo ipset add %s %s",IPTables::IPSetName(),ip.IP);
  83. } else {
  84. snprintf(command,COMMAND_SIZE,"sudo iptables -w -A INPUT -s %s -j DROP",ip.IP);
  85. }
  86. //printf("%s\n",command);
  87. command[COMMAND_SIZE-1] = 0;
  88. system(command);
  89. }
  90. // Clear the current list of IPs from iptables or ipset.
  91. void IPTables::ClearCurrent(bool useIpset)
  92. {
  93. Tree<IPAddress> ipList;
  94. if (useIpset) {
  95. ClearIPList(nullptr,useIpset);
  96. } else {
  97. ReadFromIptables(ipList,useIpset,false);
  98. ClearIPList(&(ipList.List),useIpset);
  99. }
  100. return;
  101. }
  102. // Clears a list of IPs from iptables or ipset.
  103. void IPTables::ClearIPList(std::forward_list<IPAddress*> *ipList,bool useIpset)
  104. {
  105. const int BUFFER_SIZE = 1024;
  106. char buffer[BUFFER_SIZE];
  107. if (useIpset) {
  108. if ((ipList == nullptr) || (ipList->empty())) {
  109. // Clear the entire list quickly.
  110. snprintf(buffer,BUFFER_SIZE,"sudo ipset flush %s",IPTables::IPSetName());
  111. printf("%s\n",buffer);
  112. system(buffer);
  113. } else {
  114. // Quickly remove specific items.
  115. BanIPsUsingRestore(*ipList,false);
  116. }
  117. } else {
  118. for(auto loop = ipList->begin();loop != ipList->end();++loop) {
  119. snprintf(buffer,BUFFER_SIZE,"sudo iptables -D INPUT -s %s/32 -j DROP",(*loop)->IP);
  120. printf("%s\n",buffer);
  121. system(buffer);
  122. }
  123. }
  124. }
  125. IPAddress* IPTables::Parse(const char *line,bool fromIPset)
  126. {
  127. int length;
  128. const char *search1;
  129. const char *search2;
  130. const int OFFSET = 12;
  131. IPAddress *parsed = nullptr;
  132. DEBUG;
  133. if (fromIPset) {
  134. length = strlen(line);
  135. // Remove enter character.
  136. while (length > 0) {
  137. if (line[length-1] < ' ') {
  138. length--;
  139. } else {
  140. break;
  141. }
  142. }
  143. DEBUG;
  144. parsed = new IPAddress(line,length);
  145. DEBUG;
  146. if (parsed == nullptr) {
  147. throw "Out of memory in IPAddress.Parse";
  148. }
  149. } else {
  150. if (strncmp(line,"-A INPUT -s ",OFFSET)==0) {
  151. search1 = strstr(line,"-j DROP");
  152. if (search1 != nullptr) {
  153. search2 = strstr(line,"/");
  154. if (search2 == nullptr) {
  155. length = (search1-line)-OFFSET;
  156. } else {
  157. length = (search2-line)-OFFSET;
  158. }
  159. // Remove enter character.
  160. while (length > 0) {
  161. if (line[OFFSET+length-1] < ' ') {
  162. length--;
  163. } else {
  164. break;
  165. }
  166. }
  167. DEBUG;
  168. parsed = new IPAddress(line+OFFSET,length);
  169. DEBUG;
  170. if (parsed == nullptr) {
  171. throw "Out of memory in IPAddress.Parse";
  172. }
  173. }
  174. }
  175. }
  176. return parsed;
  177. }
  178. // Reads all the IPs from the iptables program. Returns false if it ran out of memory.
  179. bool IPTables::ReadFromIptables(Tree<IPAddress> &tree,bool useIpset,bool readAll)
  180. {
  181. // If sort is true then the list is a binary tree.
  182. // If sort if false then the list is a linked list.
  183. // If duplicates != nullptr then add duplicates to this duplicates list.
  184. FILE *fInput;
  185. IPAddress *ip;
  186. const int BUFFER_SIZE = 1024;
  187. char buffer[BUFFER_SIZE];
  188. bool outOfMemory;
  189. bool foundMembers;
  190. ip = nullptr;
  191. outOfMemory = false;
  192. DEBUG;
  193. if (useIpset) {
  194. snprintf(buffer,BUFFER_SIZE,"sudo ipset list %s",IPSetName());
  195. fInput = popen(buffer,"r");
  196. foundMembers = false;
  197. } else {
  198. fInput = popen("sudo iptables -w -S","r");
  199. }
  200. if (fInput != nullptr) {
  201. DEBUG;
  202. while (fgets(buffer,BUFFER_SIZE,fInput) != nullptr) {
  203. DEBUG;
  204. if (outOfMemory) {
  205. // Keep reading even though we're out of memory.
  206. continue;
  207. }
  208. DEBUG;
  209. // Parse buffer to create an IPAddress object.
  210. if (useIpset) {
  211. // Use ipset
  212. DEBUG;
  213. if ((readAll) || (foundMembers)) {
  214. try
  215. {
  216. ip = Parse(buffer,useIpset);
  217. } catch(const char *error) {
  218. ip = nullptr;
  219. outOfMemory = true;
  220. }
  221. } else {
  222. if (strncasecmp(buffer,"Members:",8)==0) {
  223. foundMembers = true;
  224. }
  225. }
  226. } else {
  227. // Use iptables.
  228. try
  229. {
  230. ip = Parse(buffer,useIpset);
  231. } catch(const char *error) {
  232. ip = nullptr;
  233. outOfMemory = true;
  234. }
  235. }
  236. // Add the IPAddress object to the tree.
  237. DEBUG;
  238. if ((ip != nullptr) && (!outOfMemory)) {
  239. if (!tree.Add(&ip,IPAddress::Compare)) {
  240. outOfMemory = true;
  241. }
  242. }
  243. // Delete the IPAddress object if it wasn't added to the tree.
  244. if (ip != nullptr) {
  245. delete ip;
  246. ip = nullptr;
  247. }
  248. DEBUG;
  249. }
  250. DEBUG;
  251. pclose(fInput);
  252. }
  253. if (outOfMemory) {
  254. return false;
  255. }
  256. if ((useIpset) && (!foundMembers)) {
  257. // If Members: wasn't found then the set doesnt' exist. Create it.
  258. CreateIpsetSetname();
  259. MakeSureIptablesHasIpsetRule();
  260. }
  261. return true;
  262. }