icqpr.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. /*
  2. 3APA3A simpliest proxy server
  3. (c) 2002-2008 by ZARAZA <3APA3A@security.nnov.ru>
  4. please read License Agreement
  5. $Id: icqpr.c,v 1.30 2012-04-11 23:01:19 vlad Exp $
  6. */
  7. #include "proxy.h"
  8. #ifndef PORTMAP
  9. #define PORTMAP
  10. #endif
  11. #define RETURN(xxx) { param->res = xxx; goto CLEANRET; }
  12. static void hexdump(unsigned char *data, int len){
  13. for(; len; data++, len--){
  14. printf("%02x", (unsigned)*data);
  15. }
  16. printf("\n");
  17. }
  18. struct flap_header {
  19. unsigned char id;
  20. unsigned char chan;
  21. unsigned short seq;
  22. unsigned short size;
  23. char data[0];
  24. };
  25. struct snack_header {
  26. unsigned family;
  27. unsigned short flags;
  28. unsigned id;
  29. char data[0];
  30. };
  31. struct tlv_header {
  32. unsigned short type;
  33. unsigned short size;
  34. char data[0];
  35. };
  36. typedef enum {
  37. ONBEGIN = 0,
  38. ONCHAN,
  39. ONSEQ1,
  40. ONSEQ2,
  41. ONSIZE1,
  42. ONSIZE2,
  43. ONDATA
  44. } ICQSTATE;
  45. struct icqstate {
  46. ICQSTATE state;
  47. int leftinstate;
  48. unsigned short seq;
  49. unsigned short srvseq;
  50. unsigned short gotseq;
  51. unsigned short resyncseq;
  52. char channel;
  53. };
  54. typedef enum {
  55. ICQUNKNOWN,
  56. ICQCLEAR,
  57. ICQMD5,
  58. ICQCOOKIE
  59. } LOGINTYPE;
  60. struct icq_cookie {
  61. struct icq_cookie *next;
  62. char *id;
  63. int size;
  64. char * cookie;
  65. char * connectstring;
  66. };
  67. static struct icq_cookie *icq_cookies = NULL;
  68. pthread_mutex_t icq_cookie_mutex;
  69. int icq_cookie_mutex_init = 0;
  70. static void icq_clear(void *fo){
  71. };
  72. static void addbuffer(int increment, struct clientparam * param, unsigned char ** buf_p, int * bufsize_p, int * length_p){
  73. int bufsize = *length_p + increment + 40;
  74. unsigned char *newbuf;
  75. int len = 0;
  76. if(bufsize > *bufsize_p){
  77. newbuf = myalloc(bufsize);
  78. if(!newbuf) return;
  79. memcpy(newbuf, *buf_p, *length_p);
  80. myfree(*buf_p);
  81. *buf_p = newbuf;
  82. *bufsize_p = bufsize;
  83. }
  84. if(increment) len = sockrecvfrom(param->remsock, (struct sockaddr *)&param->sins, *buf_p + *length_p, increment, conf.timeouts[STRING_S]*1000);
  85. if(len > 0) {
  86. *length_p += len;
  87. param->nreads++;
  88. param->statssrv64 += len;
  89. }
  90. return;
  91. }
  92. static int searchcookie(struct clientparam *param, struct flap_header * flap, int len, int * dif, struct tlv_header *tlv, int extra){
  93. struct icq_cookie *ic;
  94. char smallbuf[64];
  95. struct tlv_header *bostlv = NULL;
  96. struct sockaddr_in sa;
  97. SASIZETYPE size = sizeof(sa);
  98. int movelen = 0;
  99. if(!icq_cookie_mutex_init){
  100. pthread_mutex_init(&icq_cookie_mutex, NULL);
  101. icq_cookie_mutex_init = 1;
  102. }
  103. pthread_mutex_lock(&icq_cookie_mutex);
  104. for(ic = icq_cookies; ic; ic = ic->next)if(!strcmp(param->username, ic->id))break;
  105. if(!ic){
  106. ic = myalloc(sizeof(struct icq_cookie));
  107. memset(ic, 0, sizeof(struct icq_cookie));
  108. ic->id = mystrdup(param->username);
  109. ic->next = icq_cookies;
  110. icq_cookies = ic;
  111. }
  112. for(; ntohs(tlv->size) < 65500 && len >= (ntohs(tlv->size) + 4); len -= (ntohs(tlv->size) + 4), tlv = (struct tlv_header *)(tlv->data + ntohs(tlv->size))){
  113. if(ntohs(tlv->type) == 0x0006){
  114. if(ic->cookie)myfree(ic->cookie);
  115. ic->cookie = myalloc(ntohs(tlv->size));
  116. memcpy(ic->cookie, tlv->data, ntohs(tlv->size));
  117. ic->size = tlv->size;
  118. }
  119. else if(ntohs(tlv->type) == 0x0005){
  120. if(ic->connectstring)myfree(ic->connectstring);
  121. ic->connectstring = myalloc(ntohs(tlv->size)+1);
  122. memcpy(ic->connectstring, tlv->data, ntohs(tlv->size));
  123. ic->connectstring[ntohs(tlv->size)] = 0;
  124. bostlv = tlv;
  125. movelen = extra + (len - 4) - ntohs(bostlv->size);
  126. }
  127. }
  128. if(!ic->connectstring || !ic->cookie){
  129. if(ic->cookie)myfree(ic->cookie);
  130. if(ic->connectstring)myfree(ic->connectstring);
  131. ic->cookie = NULL;
  132. ic->connectstring = NULL;
  133. ic->size = 0;
  134. bostlv = NULL;
  135. }
  136. pthread_mutex_unlock(&icq_cookie_mutex);
  137. if(bostlv){
  138. if(so._getsockname(param->clisock, (struct sockaddr *)&sa, &size)==-1) return 1;
  139. len = myinet_ntop(*SAFAMILY(&sa),SAADDR(&sa), smallbuf, 64);
  140. if(strchr(ic->connectstring, ':'))sprintf(smallbuf+len, ":%hu", ntohs(sa.sin_port));
  141. len = (int)strlen(smallbuf);
  142. *dif = len - (int)ntohs(bostlv->size);
  143. if(*dif != 0 && movelen > 0){
  144. memmove(bostlv->data + len, bostlv->data + ntohs(bostlv->size), movelen);
  145. }
  146. memcpy(bostlv->data, smallbuf, len);
  147. bostlv->size = htons(len);
  148. len = ((int)ntohs(flap->size)) + *dif;
  149. flap->size = htons(len);
  150. }
  151. return 0;
  152. }
  153. static FILTER_ACTION icq_srv(void *fc, struct clientparam * param, unsigned char ** buf_p, int * bufsize_p, int ioffset, int * length_p){
  154. unsigned char * start = *buf_p + ioffset;
  155. int len = *length_p - ioffset;
  156. struct icqstate *state = (struct icqstate *)fc;
  157. int size;
  158. int offset;
  159. while (len > 0){
  160. switch(state->state){
  161. case ONBEGIN:
  162. if((*start) == 0x2A) {
  163. if(len < 6){
  164. offset = (int)(start - *buf_p);
  165. addbuffer(6-len, param, buf_p, bufsize_p, length_p);
  166. start = *buf_p + offset;
  167. len = (int)(*buf_p + *length_p - start);
  168. }
  169. state->state = ONCHAN;
  170. }
  171. else {
  172. if(!state->leftinstate)param->srv->logfunc(param, "Warning: need resync");
  173. state->leftinstate++;
  174. if(state->leftinstate > 65535){
  175. param->srv->logfunc(param, "Out of Sync");
  176. return REJECT;
  177. }
  178. }
  179. start++;
  180. len--;
  181. break;
  182. case ONCHAN:
  183. if (*start >= 10){
  184. param->srv->logfunc(param, "Warning: Wrong channel");
  185. state->state = ONBEGIN;
  186. }
  187. else {
  188. state->state = ONSEQ1;
  189. state->channel = *start;
  190. start++;
  191. len--;
  192. }
  193. break;
  194. case ONSEQ1:
  195. state->gotseq = (((unsigned)*start) << 8);
  196. state->state = ONSEQ2;
  197. *(start) = (state->seq>>8);
  198. start++;
  199. len--;
  200. break;
  201. case ONSEQ2:
  202. state->gotseq += *start;
  203. if(state->gotseq != state->srvseq){
  204. char smallbuf[64];
  205. if(((state->gotseq < state->srvseq) || ((state->gotseq - state->srvseq) > 10 )) && (!state->resyncseq || state->gotseq != state->resyncseq)){
  206. sprintf(smallbuf, "Warning: Wrong sequence, expected: %04hx got: %04hx", state->srvseq, state->gotseq);
  207. param->srv->logfunc(param, smallbuf);
  208. state->state = ONBEGIN;
  209. state->resyncseq = state->gotseq;
  210. break;
  211. }
  212. sprintf(smallbuf, "Warning: %hu flaps are lost on resync", state->gotseq - state->srvseq );
  213. param->srv->logfunc(param, smallbuf);
  214. state->srvseq = state->gotseq;
  215. *(start-1) = (state->seq>>8);
  216. }
  217. *start = (state->seq & 0x00FF);
  218. state->srvseq = state->srvseq + 1;
  219. state->seq = state->seq + 1;
  220. state->state = ONSIZE1;
  221. start++;
  222. len--;
  223. break;
  224. case ONSIZE1:
  225. state->leftinstate = (((unsigned)(*start))<<8);
  226. state->state = ONSIZE2;
  227. start++;
  228. len--;
  229. break;
  230. case ONSIZE2:
  231. state->leftinstate += *start;
  232. state->state = (state->leftinstate)?ONDATA:ONBEGIN;
  233. start++;
  234. len--;
  235. if(state->leftinstate > 30 && state->channel == 2) {
  236. if(len < state->leftinstate) {
  237. offset = (int)(start - *buf_p);
  238. addbuffer(state->leftinstate - len, param, buf_p, bufsize_p, length_p);
  239. start = *buf_p + offset;
  240. len = (int)(*length_p - offset);
  241. }
  242. size = 0;
  243. if ((start[4] & 0x80)) {
  244. size = htons(*(unsigned short *)(start+10)) + 2;
  245. if(size > 8) size = 0;
  246. }
  247. if (start[0] == 0 && start[1] == 1 &&
  248. ((start[2] == 0 && start[3] == 5) || (start[2] == 1 && start[3] == 2))){
  249. int dif = 0;
  250. offset = (int)(start - *buf_p);
  251. addbuffer(0, param, buf_p, bufsize_p, length_p);
  252. start = *buf_p + offset;
  253. searchcookie(param, (struct flap_header *) (start-6), state->leftinstate-(size+10), &dif, (struct tlv_header *) (start + size + 10), len - state->leftinstate);
  254. *length_p += dif;
  255. start += (state->leftinstate + dif);
  256. len -= state->leftinstate;
  257. state->leftinstate = 0;
  258. state->state = ONBEGIN;
  259. }
  260. }
  261. break;
  262. case ONDATA:
  263. size = (state->leftinstate > len)? len : state->leftinstate;
  264. start += size;
  265. len -= size;
  266. state->leftinstate -= size;
  267. if(!state->leftinstate) {
  268. state->state = ONBEGIN;
  269. }
  270. break;
  271. }
  272. }
  273. return CONTINUE;
  274. }
  275. static struct filter icqfilter = {
  276. NULL,
  277. "icqfilter",
  278. NULL,
  279. NULL,
  280. NULL,
  281. NULL,
  282. NULL,
  283. NULL,
  284. NULL,
  285. NULL,
  286. *icq_srv,
  287. *icq_clear,
  288. NULL
  289. };
  290. static int readflap(struct clientparam * param, int direction, unsigned char *buf, int buflen){
  291. int i, len;
  292. struct flap_header *flap = (struct flap_header *)buf;
  293. i = sockgetlinebuf(param, direction, buf, 6, EOF, conf.timeouts[STRING_L]);
  294. if(i!=6) return 1;
  295. if(flap->id != 0x2a) return 2;
  296. len = ntohs(flap->size);
  297. if(len > buflen-6) return 3;
  298. i = sockgetlinebuf(param, direction, flap->data, len, EOF, conf.timeouts[STRING_S]);
  299. if(len != i) return 4;
  300. return 0;
  301. }
  302. #define flap ((struct flap_header *)buf)
  303. #define snack ((struct snack_header *)(buf+6))
  304. void * icqprchild(struct clientparam* param) {
  305. int res;
  306. unsigned char tmpsend[1024];
  307. unsigned char *buf;
  308. int i,j,len,len1;
  309. int offset = 0;
  310. int buflen = 16384;
  311. LOGINTYPE logintype = ICQUNKNOWN;
  312. int greet = 0;
  313. struct icq_cookie *ic;
  314. struct tlv_header *tlv;
  315. struct icqstate mystate = {
  316. ONBEGIN,
  317. 0, 0, 0,
  318. 0
  319. };
  320. struct filterp icqfilterp = {
  321. &icqfilter,
  322. (void *)&mystate
  323. };
  324. struct filterp **newfilters;
  325. char handshake[] = {'\052', '\001', '\000', '\000', '\000', '\004', '\000', '\000', '\000', '\001'};
  326. memcpy(tmpsend, handshake, 10);
  327. if(socksend(param->clisock, tmpsend, 10, conf.timeouts[STRING_S])!=10) {RETURN (1101);}
  328. buf = myalloc(65600);
  329. if((res = readflap(param, CLIENT, buf, 1000))) {RETURN (1180 + res);}
  330. if(ntohs(flap->size) == 4 || ntohs(flap->size) == 12){
  331. tmpsend[2] = buf[2];
  332. tmpsend[3] = buf[3];
  333. greet = 1;
  334. if(readflap(param, CLIENT, buf, 65550)) {RETURN (110);}
  335. }
  336. if(flap->chan != 1 && (flap->chan != 2 || snack->family != htonl(0x00170006))){
  337. RETURN(1104);
  338. }
  339. len = ntohs(flap->size);
  340. if(flap->chan == 1){
  341. tlv = (struct tlv_header *)(flap->data + 4);
  342. len -= 4;
  343. }
  344. else {
  345. tlv = (struct tlv_header *)(flap->data + 10);
  346. len -= 10;
  347. }
  348. for(; len >= (ntohs(tlv->size) + 4); len -= (ntohs(tlv->size) + 4), tlv = (struct tlv_header *)(tlv->data + ntohs(tlv->size))){
  349. switch(ntohs(tlv->type)){
  350. case 0x0001:
  351. if(flap->chan == 2 && !logintype)logintype = ICQMD5;
  352. if(!param->username){
  353. param->username = myalloc(ntohs(tlv->size) + 1);
  354. for(i=0, j=0; i < ntohs(tlv->size); i++){
  355. if(!isspace(tlv->data[i]))param->username[j++]=tolower(tlv->data[i]);
  356. }
  357. param->username[j] = 0;
  358. }
  359. break;
  360. case 0x0002:
  361. logintype = ICQCLEAR;
  362. break;
  363. case 0x0006:
  364. logintype = ICQCOOKIE;
  365. for(ic = icq_cookies; ic; ic=ic->next){
  366. if(ic->size && ic->size == tlv->size && !memcmp(ic->cookie, tlv->data, ntohs(tlv->size))){
  367. parsehostname((char *)ic->connectstring, param, ntohs(param->srv->targetport));
  368. if(!param->username && ic->id) param->username = mystrdup(ic->id);
  369. break;
  370. }
  371. }
  372. if(!ic) RETURN(1132);
  373. break;
  374. }
  375. }
  376. if(!logintype) RETURN(1133);
  377. if(logintype != ICQCOOKIE) {
  378. parsehostname((char *)param->srv->target, param, ntohs(param->srv->targetport));
  379. }
  380. param->operation = CONNECT;
  381. res = (*param->srv->authfunc)(param);
  382. if(res) {RETURN(res);}
  383. if(greet){
  384. if(socksend(param->remsock, tmpsend, 10, conf.timeouts[STRING_S])!=10) {RETURN (1105);}
  385. param->statscli64 += 10;
  386. }
  387. if(readflap(param, SERVER, tmpsend, 1024)) {RETURN (1111);}
  388. param->statssrv64 += (ntohs(((struct flap_header *)tmpsend)->size) + 6);
  389. mystate.srvseq = ntohs(((struct flap_header *)tmpsend)->seq) + 1;
  390. mystate.seq = 1;
  391. len = ntohs(flap->size) + 6;
  392. if((res=handledatfltcli(param, &buf, &buflen, offset, &len))!=PASS) RETURN(res);
  393. if(socksend(param->remsock, buf+offset, len, conf.timeouts[STRING_S])!=(ntohs(flap->size)+6)) {RETURN (1106);}
  394. offset = 0;
  395. param->statscli64 += len;
  396. if(logintype == ICQMD5) {
  397. if(readflap(param, SERVER, buf, 65550)) {RETURN (1112);}
  398. mystate.srvseq = ntohs(flap->seq) + 1;
  399. flap->seq = htons(mystate.seq);
  400. mystate.seq++;
  401. len = ntohs(flap->size) + 6;
  402. if((res=handledatfltsrv(param, &buf, &buflen, offset, &len))!=PASS) RETURN(res);
  403. if(socksend(param->clisock, buf+offset, len, conf.timeouts[STRING_S])!=len) {RETURN (1113);}
  404. offset = 0;
  405. if(readflap(param, CLIENT, buf, 65550)) {RETURN (1114);}
  406. len = ntohs(flap->size) + 6;
  407. if((res=handledatfltcli(param, &buf, &buflen, offset, &len))!=PASS) RETURN(res);
  408. if(socksend(param->remsock, buf+offset, len, conf.timeouts[STRING_S])!=len) {RETURN (1115);}
  409. param->statscli64 += len;
  410. offset = 0;
  411. }
  412. if(logintype != ICQCOOKIE) {
  413. if(readflap(param, SERVER, buf, 65550)) {RETURN (1116);}
  414. mystate.srvseq = ntohs(flap->seq) + 1;
  415. flap->seq = htons(mystate.seq);
  416. mystate.seq++;
  417. len = ntohs(flap->size);
  418. if(!param->username) {RETURN (1117);}
  419. if(flap->chan == 1 || flap->chan == 4){
  420. if(flap->data[0] == 0 && flap->data[1] == 0 && flap->data[2] == 0 && flap->data[3] == 1){
  421. tlv = (struct tlv_header *)(flap->data + 4);
  422. len -= 4;
  423. }
  424. else
  425. tlv = (struct tlv_header *)(flap->data);
  426. }
  427. else {
  428. tlv = (struct tlv_header *)(flap->data + 10);
  429. len -= 10;
  430. }
  431. len1 = ntohs(flap->size);
  432. if(searchcookie(param, flap, len, &len1, tlv, 0)){RETURN (1118);}
  433. len = ntohs(flap->size) + 6;
  434. if((res=handledatfltsrv(param, &buf, &buflen, offset, &len))!=PASS) RETURN(res);
  435. if(socksend(param->clisock, buf+offset, len, conf.timeouts[STRING_S])!=len) {RETURN (1117);}
  436. offset = 0;
  437. }
  438. param->ndatfilterssrv++;
  439. newfilters = myalloc(param->ndatfilterssrv * sizeof(struct filterp *));
  440. if(param->ndatfilterssrv > 1){
  441. memcpy(newfilters, param->datfilterssrv, (param->ndatfilterssrv - 1) * sizeof(struct filterp *));
  442. myfree(param->datfilterssrv);
  443. }
  444. param->datfilterssrv = newfilters;
  445. newfilters[param->ndatfilterssrv - 1] = &icqfilterp;
  446. param->res = sockmap(param, conf.timeouts[CONNECTION_L]);
  447. param->ndatfilterssrv--;
  448. CLEANRET:
  449. (*param->srv->logfunc)(param, NULL);
  450. freeparam(param);
  451. if(buf) myfree(buf);
  452. return (NULL);
  453. }
  454. #ifdef WITHMAIN
  455. struct proxydef childdef = {
  456. icqprchild,
  457. 0,
  458. 0,
  459. S_ICQPR,
  460. ""
  461. };
  462. #include "proxymain.c"
  463. #endif