icqpr.c 14 KB

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