add proxychain example
[rofl0r-rocksock.git] / examples / proxychain.c
blob9db875b8c752b3991db6d7e7eb1b87e96712d3fc
1 /*
3 * author: rofl0r
5 * License: LGPL 2.1+ with static linking exception
8 */
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <pthread.h>
14 #include <errno.h>
15 #include <time.h>
16 #include <unistd.h>
17 #include "../rocksock.h"
18 #include "../../lib/include/stringlist.h"
20 static int timeout;
21 static char chk_host[512];
22 static int chk_host_port;
23 static int debug = 1;
25 #define DPRINTF(fmt, args...) if(debug) do { dprintf(2,fmt, ## args); } while(0)
27 static int scanHost(stringlist* chain, char* scanproxy, size_t max, rs_errorInfo *e_info) {
28 rocksock skt;
29 rocksock* soc = &skt;
30 int ret;
32 rs_proxy proxies[stringlist_getsize(chain)+1];
34 rocksock_init(soc, proxies);
35 rocksock_set_timeout(soc, timeout);
37 DPRINTF("====== checking %s (timeout: %d)\n", scanproxy, timeout);
39 size_t i, top = max == -1 ? stringlist_getsize(chain) : max;
40 char *candidate;
41 for(i = 0; i < top; i++) {
42 // stringlist_foreach(chain, candidate) {
43 candidate = stringlist_get(chain, i);
44 DPRINTF("> %s\n", candidate);
45 if(rocksock_add_proxy_fromstring(soc, candidate))
46 return -1;
49 if(rocksock_add_proxy_fromstring(soc, scanproxy))
50 return -1;
52 if (!rocksock_connect(soc, chk_host, chk_host_port, 0)){
53 DPRINTF("SUCCESS\n");
54 ret = 0; /* success */
55 } else {
56 char ebuf[256];
57 DPRINTF("%s\n", rocksock_strerror_detailed(soc, ebuf, sizeof ebuf));
58 *e_info = soc->lasterror;
59 ret = -1;
62 rocksock_disconnect(soc);
63 rocksock_clear(soc);
65 return ret;
68 static int usage(const char *argv0) {
69 dprintf(2,
70 "proxy checker/chain generator.\n\n"
72 "%s [options] chain-length\n"
73 "[-c check_ip:port]\n"
74 "[-T global timeout_in_millisec]\n"
75 "[-t per-proxy additional timeout_in_millisec]\n"
76 "[-l fixedlist.txt]\n"
77 "\n"
79 "generates a working proxychain.\n"
80 "every proxy that works will be added to the chain, and connects will only\n"
81 "be done through the existing chain.\n"
82 "if the desired chain length is reached, the chain will be printed to stdout.\n"
83 "the list of proxies is passed on stdin in type://ip:port format, where type\n"
84 "can be one of socks4|socks5|http\n"
85 "the optional list added with -l contains proxies that will be added w/o check\n"
86 "\n"
88 "timeout defaults to 1500.\n"
89 "checkip:port defaults to cnn.com:80\n"
91 ,argv0, argv0, argv0);
92 return 1;
95 int main(int argc, char** argv) {
96 int c;
97 char *typestring = 0;
98 char *baseproxy = 0;
99 char *load_list = 0;
100 char *checkurl = "cnn.com:80";
101 int base_timeout = 1500;
102 int per_proxy_timeout = 0;
104 while ((c = getopt(argc, argv, "c:T:t:l:")) != -1) {
105 switch(c) {
106 case 'c':
107 checkurl = optarg;
108 break;
109 case 'T':
110 base_timeout = atoi(optarg);
111 break;
112 case 't':
113 per_proxy_timeout = atoi(optarg);
114 break;
115 case 'l':
116 load_list = optarg;
117 break;
118 default:
119 return usage(argv[0]);
123 if (optind >= argc) {
124 dprintf(2, "error: chain length missing\n");
125 return usage(argv[0]);
128 int n_proxies = atoi(argv[optind]);
131 char *p = strchr(checkurl, ':');
132 if(!p) return usage(argv[0]);
134 size_t l = p-checkurl;
135 strncpy(chk_host, checkurl, l);
136 chk_host[l] = 0;
137 chk_host_port = atoi(++p);
141 stringlist *chain = stringlist_new(n_proxies);
143 char buf[1024];
144 if(load_list) {
145 FILE *f = fopen(load_list, "r");
146 while(fgets(buf, sizeof buf, f)) {
147 char *p;
148 if((p = strrchr(buf, '\n'))) *p = 0;
149 if(*buf == 0 || *buf == '#') continue;
150 stringlist_add_dup(chain, buf);
154 int ret = 0;
155 while(stringlist_getsize(chain) < n_proxies) {
156 if(!fgets(buf, sizeof buf, stdin))
157 return 1;
158 char *p;
159 if((p = strrchr(buf, '\n'))) *p = 0;
160 if(*buf == 0 || *buf == '#') continue;
162 size_t i;
163 for(i=0; i < stringlist_getsize(chain); i++) {
164 char *entry = stringlist_get(chain, i);
165 if (!strcmp(entry, buf)) goto next;
168 timeout = base_timeout + (per_proxy_timeout * stringlist_getsize(chain));
169 rs_errorInfo last_err;
170 if(0 == (ret = scanHost(chain, buf, -1, &last_err)))
171 stringlist_add_dup(chain, buf);
172 else {
173 if(last_err.errortype == RS_ET_OWN &&
174 (last_err.error == RS_E_REMOTE_DISCONNECTED ||
175 last_err.error == RS_E_TARGETPROXY_CONN_REFUSED) &&
176 last_err.failedProxy != -1 && stringlist_getsize(chain) > 0
178 int fp = last_err.failedProxy, fails = 0;
179 for(i=0; i<3; i++) {
180 ret = scanHost(chain, buf, fp, &last_err);
181 if(!ret || last_err.failedProxy != fp) break;
182 fails++;
184 if(fails > 2) {
185 dprintf(2, "proxy: %d stopped working, removing\n", fp);
186 stringlist_delete(chain, fp);
190 next:;
192 char *px;
193 stringlist_foreach(chain, px) {
194 printf("%s\n", px);
196 return ret;