gnunet-gns-proxy.c 80 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2012-2014 Christian Grothoff (and other contributing authors)
  4. GNUnet is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation; either version 3, or (at your
  7. option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNUnet; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  15. Boston, MA 02111-1307, USA.
  16. */
  17. /**
  18. * @author Martin Schanzenbach
  19. * @author Christian Grothoff
  20. * @file src/gns/gnunet-gns-proxy.c
  21. * @brief HTTP(S) proxy that rewrites URIs and fakes certificats to make GNS work
  22. * with legacy browsers
  23. *
  24. * TODO:
  25. * - double-check queueing logic
  26. */
  27. #include "platform.h"
  28. #include <microhttpd.h>
  29. #if HAVE_CURL_CURL_H
  30. #include <curl/curl.h>
  31. #elif HAVE_GNURL_CURL_H
  32. #include <gnurl/curl.h>
  33. #endif
  34. #include <gnutls/gnutls.h>
  35. #include <gnutls/x509.h>
  36. #include <gnutls/abstract.h>
  37. #include <gnutls/crypto.h>
  38. #if HAVE_GNUTLS_DANE
  39. #include <gnutls/dane.h>
  40. #endif
  41. #include <regex.h>
  42. #include "gnunet_util_lib.h"
  43. #include "gnunet_gns_service.h"
  44. #include "gnunet_identity_service.h"
  45. #include "gns.h"
  46. /**
  47. * Default Socks5 listen port.
  48. */
  49. #define GNUNET_GNS_PROXY_PORT 7777
  50. /**
  51. * Maximum supported length for a URI.
  52. * Should die. @deprecated
  53. */
  54. #define MAX_HTTP_URI_LENGTH 2048
  55. /**
  56. * Size of the buffer for the data upload / download. Must be
  57. * enough for curl, thus CURL_MAX_WRITE_SIZE is needed here (16k).
  58. */
  59. #define IO_BUFFERSIZE CURL_MAX_WRITE_SIZE
  60. /**
  61. * Size of the read/write buffers for Socks. Uses
  62. * 256 bytes for the hostname (at most), plus a few
  63. * bytes overhead for the messages.
  64. */
  65. #define SOCKS_BUFFERSIZE (256 + 32)
  66. /**
  67. * Port for plaintext HTTP.
  68. */
  69. #define HTTP_PORT 80
  70. /**
  71. * Port for HTTPS.
  72. */
  73. #define HTTPS_PORT 443
  74. /**
  75. * Largest allowed size for a PEM certificate.
  76. */
  77. #define MAX_PEM_SIZE (10 * 1024)
  78. /**
  79. * After how long do we clean up unused MHD SSL/TLS instances?
  80. */
  81. #define MHD_CACHE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
  82. /**
  83. * After how long do we clean up Socks5 handles that failed to show any activity
  84. * with their respective MHD instance?
  85. */
  86. #define HTTP_HANDSHAKE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
  87. /**
  88. * Log curl error.
  89. *
  90. * @param level log level
  91. * @param fun name of curl_easy-function that gave the error
  92. * @param rc return code from curl
  93. */
  94. #define LOG_CURL_EASY(level,fun,rc) GNUNET_log(level, _("%s failed at %s:%d: `%s'\n"), fun, __FILE__, __LINE__, curl_easy_strerror (rc))
  95. /* *************** Socks protocol definitions (move to TUN?) ****************** */
  96. /**
  97. * Which SOCKS version do we speak?
  98. */
  99. #define SOCKS_VERSION_5 0x05
  100. /**
  101. * Flag to set for 'no authentication'.
  102. */
  103. #define SOCKS_AUTH_NONE 0
  104. /**
  105. * Commands in Socks5.
  106. */
  107. enum Socks5Commands
  108. {
  109. /**
  110. * Establish TCP/IP stream.
  111. */
  112. SOCKS5_CMD_TCP_STREAM = 1,
  113. /**
  114. * Establish TCP port binding.
  115. */
  116. SOCKS5_CMD_TCP_PORT = 2,
  117. /**
  118. * Establish UDP port binding.
  119. */
  120. SOCKS5_CMD_UDP_PORT = 3
  121. };
  122. /**
  123. * Address types in Socks5.
  124. */
  125. enum Socks5AddressType
  126. {
  127. /**
  128. * IPv4 address.
  129. */
  130. SOCKS5_AT_IPV4 = 1,
  131. /**
  132. * IPv4 address.
  133. */
  134. SOCKS5_AT_DOMAINNAME = 3,
  135. /**
  136. * IPv6 address.
  137. */
  138. SOCKS5_AT_IPV6 = 4
  139. };
  140. /**
  141. * Status codes in Socks5 response.
  142. */
  143. enum Socks5StatusCode
  144. {
  145. SOCKS5_STATUS_REQUEST_GRANTED = 0,
  146. SOCKS5_STATUS_GENERAL_FAILURE = 1,
  147. SOCKS5_STATUS_CONNECTION_NOT_ALLOWED_BY_RULE = 2,
  148. SOCKS5_STATUS_NETWORK_UNREACHABLE = 3,
  149. SOCKS5_STATUS_HOST_UNREACHABLE = 4,
  150. SOCKS5_STATUS_CONNECTION_REFUSED_BY_HOST = 5,
  151. SOCKS5_STATUS_TTL_EXPIRED = 6,
  152. SOCKS5_STATUS_COMMAND_NOT_SUPPORTED = 7,
  153. SOCKS5_STATUS_ADDRESS_TYPE_NOT_SUPPORTED = 8
  154. };
  155. /**
  156. * Client hello in Socks5 protocol.
  157. */
  158. struct Socks5ClientHelloMessage
  159. {
  160. /**
  161. * Should be #SOCKS_VERSION_5.
  162. */
  163. uint8_t version;
  164. /**
  165. * How many authentication methods does the client support.
  166. */
  167. uint8_t num_auth_methods;
  168. /* followed by supported authentication methods, 1 byte per method */
  169. };
  170. /**
  171. * Server hello in Socks5 protocol.
  172. */
  173. struct Socks5ServerHelloMessage
  174. {
  175. /**
  176. * Should be #SOCKS_VERSION_5.
  177. */
  178. uint8_t version;
  179. /**
  180. * Chosen authentication method, for us always #SOCKS_AUTH_NONE,
  181. * which skips the authentication step.
  182. */
  183. uint8_t auth_method;
  184. };
  185. /**
  186. * Client socks request in Socks5 protocol.
  187. */
  188. struct Socks5ClientRequestMessage
  189. {
  190. /**
  191. * Should be #SOCKS_VERSION_5.
  192. */
  193. uint8_t version;
  194. /**
  195. * Command code, we only uspport #SOCKS5_CMD_TCP_STREAM.
  196. */
  197. uint8_t command;
  198. /**
  199. * Reserved, always zero.
  200. */
  201. uint8_t resvd;
  202. /**
  203. * Address type, an `enum Socks5AddressType`.
  204. */
  205. uint8_t addr_type;
  206. /*
  207. * Followed by either an ip4/ipv6 address or a domain name with a
  208. * length field (uint8_t) in front (depending on @e addr_type).
  209. * followed by port number in network byte order (uint16_t).
  210. */
  211. };
  212. /**
  213. * Server response to client requests in Socks5 protocol.
  214. */
  215. struct Socks5ServerResponseMessage
  216. {
  217. /**
  218. * Should be #SOCKS_VERSION_5.
  219. */
  220. uint8_t version;
  221. /**
  222. * Status code, an `enum Socks5StatusCode`
  223. */
  224. uint8_t reply;
  225. /**
  226. * Always zero.
  227. */
  228. uint8_t reserved;
  229. /**
  230. * Address type, an `enum Socks5AddressType`.
  231. */
  232. uint8_t addr_type;
  233. /*
  234. * Followed by either an ip4/ipv6 address or a domain name with a
  235. * length field (uint8_t) in front (depending on @e addr_type).
  236. * followed by port number in network byte order (uint16_t).
  237. */
  238. };
  239. /* *********************** Datastructures for HTTP handling ****************** */
  240. /**
  241. * A structure for CA cert/key
  242. */
  243. struct ProxyCA
  244. {
  245. /**
  246. * The certificate
  247. */
  248. gnutls_x509_crt_t cert;
  249. /**
  250. * The private key
  251. */
  252. gnutls_x509_privkey_t key;
  253. };
  254. /**
  255. * Structure for GNS certificates
  256. */
  257. struct ProxyGNSCertificate
  258. {
  259. /**
  260. * The certificate as PEM
  261. */
  262. char cert[MAX_PEM_SIZE];
  263. /**
  264. * The private key as PEM
  265. */
  266. char key[MAX_PEM_SIZE];
  267. };
  268. /**
  269. * A structure for all running Httpds
  270. */
  271. struct MhdHttpList
  272. {
  273. /**
  274. * DLL for httpds
  275. */
  276. struct MhdHttpList *prev;
  277. /**
  278. * DLL for httpds
  279. */
  280. struct MhdHttpList *next;
  281. /**
  282. * the domain name to server (only important for SSL)
  283. */
  284. char *domain;
  285. /**
  286. * The daemon handle
  287. */
  288. struct MHD_Daemon *daemon;
  289. /**
  290. * Optional proxy certificate used
  291. */
  292. struct ProxyGNSCertificate *proxy_cert;
  293. /**
  294. * The task ID
  295. */
  296. struct GNUNET_SCHEDULER_Task * httpd_task;
  297. /**
  298. * is this an ssl daemon?
  299. */
  300. int is_ssl;
  301. };
  302. /* ***************** Datastructures for Socks handling **************** */
  303. /**
  304. * The socks phases.
  305. */
  306. enum SocksPhase
  307. {
  308. /**
  309. * We're waiting to get the client hello.
  310. */
  311. SOCKS5_INIT,
  312. /**
  313. * We're waiting to get the initial request.
  314. */
  315. SOCKS5_REQUEST,
  316. /**
  317. * We are currently resolving the destination.
  318. */
  319. SOCKS5_RESOLVING,
  320. /**
  321. * We're in transfer mode.
  322. */
  323. SOCKS5_DATA_TRANSFER,
  324. /**
  325. * Finish writing the write buffer, then clean up.
  326. */
  327. SOCKS5_WRITE_THEN_CLEANUP,
  328. /**
  329. * Socket has been passed to MHD, do not close it anymore.
  330. */
  331. SOCKS5_SOCKET_WITH_MHD,
  332. /**
  333. * We've finished receiving upload data from MHD.
  334. */
  335. SOCKS5_SOCKET_UPLOAD_STARTED,
  336. /**
  337. * We've finished receiving upload data from MHD.
  338. */
  339. SOCKS5_SOCKET_UPLOAD_DONE,
  340. /**
  341. * We've finished uploading data via CURL and can now download.
  342. */
  343. SOCKS5_SOCKET_DOWNLOAD_STARTED,
  344. /**
  345. * We've finished receiving download data from cURL.
  346. */
  347. SOCKS5_SOCKET_DOWNLOAD_DONE
  348. };
  349. /**
  350. * A structure for socks requests
  351. */
  352. struct Socks5Request
  353. {
  354. /**
  355. * DLL.
  356. */
  357. struct Socks5Request *next;
  358. /**
  359. * DLL.
  360. */
  361. struct Socks5Request *prev;
  362. /**
  363. * The client socket
  364. */
  365. struct GNUNET_NETWORK_Handle *sock;
  366. /**
  367. * Handle to GNS lookup, during #SOCKS5_RESOLVING phase.
  368. */
  369. struct GNUNET_GNS_LookupRequest *gns_lookup;
  370. /**
  371. * Client socket read task
  372. */
  373. struct GNUNET_SCHEDULER_Task * rtask;
  374. /**
  375. * Client socket write task
  376. */
  377. struct GNUNET_SCHEDULER_Task * wtask;
  378. /**
  379. * Timeout task
  380. */
  381. struct GNUNET_SCHEDULER_Task * timeout_task;
  382. /**
  383. * Read buffer
  384. */
  385. char rbuf[SOCKS_BUFFERSIZE];
  386. /**
  387. * Write buffer
  388. */
  389. char wbuf[SOCKS_BUFFERSIZE];
  390. /**
  391. * Buffer we use for moving data between MHD and curl (in both directions).
  392. */
  393. char io_buf[IO_BUFFERSIZE];
  394. /**
  395. * MHD HTTP instance handling this request, NULL for none.
  396. */
  397. struct MhdHttpList *hd;
  398. /**
  399. * MHD response object for this request.
  400. */
  401. struct MHD_Response *response;
  402. /**
  403. * the domain name to server (only important for SSL)
  404. */
  405. char *domain;
  406. /**
  407. * DNS Legacy Host Name as given by GNS, NULL if not given.
  408. */
  409. char *leho;
  410. /**
  411. * Payload of the (last) DANE record encountered.
  412. */
  413. char *dane_data;
  414. /**
  415. * The URL to fetch
  416. */
  417. char *url;
  418. /**
  419. * Handle to cURL
  420. */
  421. CURL *curl;
  422. /**
  423. * HTTP request headers for the curl request.
  424. */
  425. struct curl_slist *headers;
  426. /**
  427. * DNS->IP mappings resolved through GNS
  428. */
  429. struct curl_slist *hosts;
  430. /**
  431. * HTTP response code to give to MHD for the response.
  432. */
  433. unsigned int response_code;
  434. /**
  435. * Number of bytes in @e dane_data.
  436. */
  437. size_t dane_data_len;
  438. /**
  439. * Number of bytes already in read buffer
  440. */
  441. size_t rbuf_len;
  442. /**
  443. * Number of bytes already in write buffer
  444. */
  445. size_t wbuf_len;
  446. /**
  447. * Number of bytes already in the IO buffer.
  448. */
  449. size_t io_len;
  450. /**
  451. * Once known, what's the target address for the connection?
  452. */
  453. struct sockaddr_storage destination_address;
  454. /**
  455. * The socks state
  456. */
  457. enum SocksPhase state;
  458. /**
  459. * Desired destination port.
  460. */
  461. uint16_t port;
  462. };
  463. /* *********************** Globals **************************** */
  464. /**
  465. * The port the proxy is running on (default 7777)
  466. */
  467. static unsigned long port = GNUNET_GNS_PROXY_PORT;
  468. /**
  469. * The CA file (pem) to use for the proxy CA
  470. */
  471. static char *cafile_opt;
  472. /**
  473. * The listen socket of the proxy for IPv4
  474. */
  475. static struct GNUNET_NETWORK_Handle *lsock4;
  476. /**
  477. * The listen socket of the proxy for IPv6
  478. */
  479. static struct GNUNET_NETWORK_Handle *lsock6;
  480. /**
  481. * The listen task ID for IPv4
  482. */
  483. static struct GNUNET_SCHEDULER_Task * ltask4;
  484. /**
  485. * The listen task ID for IPv6
  486. */
  487. static struct GNUNET_SCHEDULER_Task * ltask6;
  488. /**
  489. * The cURL download task (curl multi API).
  490. */
  491. static struct GNUNET_SCHEDULER_Task * curl_download_task;
  492. /**
  493. * The cURL multi handle
  494. */
  495. static CURLM *curl_multi;
  496. /**
  497. * Handle to the GNS service
  498. */
  499. static struct GNUNET_GNS_Handle *gns_handle;
  500. /**
  501. * DLL for http/https daemons
  502. */
  503. static struct MhdHttpList *mhd_httpd_head;
  504. /**
  505. * DLL for http/https daemons
  506. */
  507. static struct MhdHttpList *mhd_httpd_tail;
  508. /**
  509. * Daemon for HTTP (we have one per SSL certificate, and then one for
  510. * all HTTP connections; this is the one for HTTP, not HTTPS).
  511. */
  512. static struct MhdHttpList *httpd;
  513. /**
  514. * DLL of active socks requests.
  515. */
  516. static struct Socks5Request *s5r_head;
  517. /**
  518. * DLL of active socks requests.
  519. */
  520. static struct Socks5Request *s5r_tail;
  521. /**
  522. * The users local GNS master zone
  523. */
  524. static struct GNUNET_CRYPTO_EcdsaPublicKey local_gns_zone;
  525. /**
  526. * The users local shorten zone
  527. */
  528. static struct GNUNET_CRYPTO_EcdsaPrivateKey local_shorten_zone;
  529. /**
  530. * Is shortening enabled?
  531. */
  532. static int do_shorten;
  533. /**
  534. * The CA for SSL certificate generation
  535. */
  536. static struct ProxyCA proxy_ca;
  537. /**
  538. * Response we return on cURL failures.
  539. */
  540. static struct MHD_Response *curl_failure_response;
  541. /**
  542. * Connection to identity service.
  543. */
  544. static struct GNUNET_IDENTITY_Handle *identity;
  545. /**
  546. * Request for our ego.
  547. */
  548. static struct GNUNET_IDENTITY_Operation *id_op;
  549. /**
  550. * Our configuration.
  551. */
  552. static const struct GNUNET_CONFIGURATION_Handle *cfg;
  553. /* ************************* Global helpers ********************* */
  554. /**
  555. * Run MHD now, we have extra data ready for the callback.
  556. *
  557. * @param hd the daemon to run now.
  558. */
  559. static void
  560. run_mhd_now (struct MhdHttpList *hd);
  561. /**
  562. * Clean up s5r handles.
  563. *
  564. * @param s5r the handle to destroy
  565. */
  566. static void
  567. cleanup_s5r (struct Socks5Request *s5r)
  568. {
  569. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  570. "Cleaning up socks request\n");
  571. if (NULL != s5r->curl)
  572. {
  573. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  574. "Cleaning up cURL handle\n");
  575. curl_multi_remove_handle (curl_multi, s5r->curl);
  576. curl_easy_cleanup (s5r->curl);
  577. s5r->curl = NULL;
  578. }
  579. curl_slist_free_all (s5r->headers);
  580. if (NULL != s5r->hosts)
  581. {
  582. curl_slist_free_all (s5r->hosts);
  583. }
  584. if ( (NULL != s5r->response) &&
  585. (curl_failure_response != s5r->response) )
  586. MHD_destroy_response (s5r->response);
  587. if (NULL != s5r->rtask)
  588. GNUNET_SCHEDULER_cancel (s5r->rtask);
  589. if (NULL != s5r->timeout_task)
  590. GNUNET_SCHEDULER_cancel (s5r->timeout_task);
  591. if (NULL != s5r->wtask)
  592. GNUNET_SCHEDULER_cancel (s5r->wtask);
  593. if (NULL != s5r->gns_lookup)
  594. GNUNET_GNS_lookup_cancel (s5r->gns_lookup);
  595. if (NULL != s5r->sock)
  596. {
  597. if (SOCKS5_SOCKET_WITH_MHD <= s5r->state)
  598. GNUNET_NETWORK_socket_free_memory_only_ (s5r->sock);
  599. else
  600. GNUNET_NETWORK_socket_close (s5r->sock);
  601. }
  602. GNUNET_CONTAINER_DLL_remove (s5r_head,
  603. s5r_tail,
  604. s5r);
  605. GNUNET_free_non_null (s5r->domain);
  606. GNUNET_free_non_null (s5r->leho);
  607. GNUNET_free_non_null (s5r->url);
  608. GNUNET_free_non_null (s5r->dane_data);
  609. GNUNET_free (s5r);
  610. }
  611. /* ************************* HTTP handling with cURL *********************** */
  612. /**
  613. * Callback for MHD response generation. This function is called from
  614. * MHD whenever MHD expects to get data back. Copies data from the
  615. * io_buf, if available.
  616. *
  617. * @param cls closure with our `struct Socks5Request`
  618. * @param pos in buffer
  619. * @param buf where to copy data
  620. * @param max available space in @a buf
  621. * @return number of bytes written to @a buf
  622. */
  623. static ssize_t
  624. mhd_content_cb (void *cls,
  625. uint64_t pos,
  626. char* buf,
  627. size_t max)
  628. {
  629. struct Socks5Request *s5r = cls;
  630. size_t bytes_to_copy;
  631. if ( (SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state) ||
  632. (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state) )
  633. {
  634. /* we're still not done with the upload, do not yet
  635. start the download, the IO buffer is still full
  636. with upload data. */
  637. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  638. "Pausing MHD download, not yet ready for download\n");
  639. return 0; /* not yet ready for data download */
  640. }
  641. bytes_to_copy = GNUNET_MIN (max,
  642. s5r->io_len);
  643. if ( (0 == bytes_to_copy) &&
  644. (SOCKS5_SOCKET_DOWNLOAD_DONE != s5r->state) )
  645. {
  646. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  647. "Pausing MHD download, no data available\n");
  648. return 0; /* more data later */
  649. }
  650. if ( (0 == bytes_to_copy) &&
  651. (SOCKS5_SOCKET_DOWNLOAD_DONE == s5r->state) )
  652. {
  653. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  654. "Completed MHD download\n");
  655. return MHD_CONTENT_READER_END_OF_STREAM;
  656. }
  657. memcpy (buf, s5r->io_buf, bytes_to_copy);
  658. memmove (s5r->io_buf,
  659. &s5r->io_buf[bytes_to_copy],
  660. s5r->io_len - bytes_to_copy);
  661. s5r->io_len -= bytes_to_copy;
  662. if (NULL != s5r->curl)
  663. curl_easy_pause (s5r->curl, CURLPAUSE_CONT);
  664. return bytes_to_copy;
  665. }
  666. /**
  667. * Check that the website has presented us with a valid SSL certificate.
  668. * The certificate must either match the domain name or the LEHO name
  669. * (or, if available, the TLSA record).
  670. *
  671. * @param s5r request to check for.
  672. * @return #GNUNET_OK if the certificate is valid
  673. */
  674. static int
  675. check_ssl_certificate (struct Socks5Request *s5r)
  676. {
  677. unsigned int cert_list_size;
  678. const gnutls_datum_t *chainp;
  679. const struct curl_tlssessioninfo *tlsinfo;
  680. char certdn[GNUNET_DNSPARSER_MAX_NAME_LENGTH + 3];
  681. size_t size;
  682. gnutls_x509_crt_t x509_cert;
  683. int rc;
  684. const char *name;
  685. if (CURLE_OK !=
  686. curl_easy_getinfo (s5r->curl,
  687. CURLINFO_TLS_SESSION,
  688. (struct curl_slist **) &tlsinfo))
  689. return GNUNET_SYSERR;
  690. if (CURLSSLBACKEND_GNUTLS != tlsinfo->backend)
  691. {
  692. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  693. _("Unsupported CURL SSL backend %d\n"),
  694. tlsinfo->backend);
  695. return GNUNET_SYSERR;
  696. }
  697. chainp = gnutls_certificate_get_peers (tlsinfo->internals, &cert_list_size);
  698. if ( (! chainp) || (0 == cert_list_size) )
  699. return GNUNET_SYSERR;
  700. size = sizeof (certdn);
  701. /* initialize an X.509 certificate structure. */
  702. gnutls_x509_crt_init (&x509_cert);
  703. gnutls_x509_crt_import (x509_cert,
  704. chainp,
  705. GNUTLS_X509_FMT_DER);
  706. if (0 != (rc = gnutls_x509_crt_get_dn_by_oid (x509_cert,
  707. GNUTLS_OID_X520_COMMON_NAME,
  708. 0, /* the first and only one */
  709. 0 /* no DER encoding */,
  710. certdn,
  711. &size)))
  712. {
  713. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  714. _("Failed to fetch CN from cert: %s\n"),
  715. gnutls_strerror(rc));
  716. gnutls_x509_crt_deinit (x509_cert);
  717. return GNUNET_SYSERR;
  718. }
  719. /* check for TLSA/DANE records */
  720. #if HAVE_GNUTLS_DANE
  721. if (NULL != s5r->dane_data)
  722. {
  723. char *dd[] = { s5r->dane_data, NULL };
  724. int dlen[] = { s5r->dane_data_len, 0};
  725. dane_state_t dane_state;
  726. dane_query_t dane_query;
  727. unsigned int verify;
  728. /* FIXME: add flags to gnutls to NOT read UNBOUND_ROOT_KEY_FILE here! */
  729. if (0 != (rc = dane_state_init (&dane_state,
  730. #ifdef DANE_F_IGNORE_DNSSEC
  731. DANE_F_IGNORE_DNSSEC |
  732. #endif
  733. DANE_F_IGNORE_LOCAL_RESOLVER)))
  734. {
  735. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  736. _("Failed to initialize DANE: %s\n"),
  737. dane_strerror(rc));
  738. gnutls_x509_crt_deinit (x509_cert);
  739. return GNUNET_SYSERR;
  740. }
  741. if (0 != (rc = dane_raw_tlsa (dane_state,
  742. &dane_query,
  743. dd,
  744. dlen,
  745. GNUNET_YES,
  746. GNUNET_NO)))
  747. {
  748. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  749. _("Failed to parse DANE record: %s\n"),
  750. dane_strerror(rc));
  751. dane_state_deinit (dane_state);
  752. gnutls_x509_crt_deinit (x509_cert);
  753. return GNUNET_SYSERR;
  754. }
  755. if (0 != (rc = dane_verify_crt_raw (dane_state,
  756. chainp,
  757. cert_list_size,
  758. gnutls_certificate_type_get (tlsinfo->internals),
  759. dane_query,
  760. 0, 0,
  761. &verify)))
  762. {
  763. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  764. _("Failed to verify TLS connection using DANE: %s\n"),
  765. dane_strerror(rc));
  766. dane_query_deinit (dane_query);
  767. dane_state_deinit (dane_state);
  768. gnutls_x509_crt_deinit (x509_cert);
  769. return GNUNET_SYSERR;
  770. }
  771. if (0 != verify)
  772. {
  773. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  774. _("Failed DANE verification failed with GnuTLS verify status code: %u\n"),
  775. verify);
  776. dane_query_deinit (dane_query);
  777. dane_state_deinit (dane_state);
  778. gnutls_x509_crt_deinit (x509_cert);
  779. return GNUNET_SYSERR;
  780. }
  781. dane_query_deinit (dane_query);
  782. dane_state_deinit (dane_state);
  783. /* success! */
  784. }
  785. else
  786. #endif
  787. {
  788. /* try LEHO or ordinary domain name X509 verification */
  789. name = s5r->domain;
  790. if (NULL != s5r->leho)
  791. name = s5r->leho;
  792. if (NULL != name)
  793. {
  794. if (0 == (rc = gnutls_x509_crt_check_hostname (x509_cert,
  795. name)))
  796. {
  797. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  798. _("SSL certificate subject name (%s) does not match `%s'\n"),
  799. certdn,
  800. name);
  801. gnutls_x509_crt_deinit (x509_cert);
  802. return GNUNET_SYSERR;
  803. }
  804. }
  805. else
  806. {
  807. /* we did not even have the domain name!? */
  808. GNUNET_break (0);
  809. return GNUNET_SYSERR;
  810. }
  811. }
  812. gnutls_x509_crt_deinit (x509_cert);
  813. return GNUNET_OK;
  814. }
  815. /**
  816. * We're getting an HTTP response header from cURL. Convert it to the
  817. * MHD response headers. Mostly copies the headers, but makes special
  818. * adjustments to "Set-Cookie" and "Location" headers as those may need
  819. * to be changed from the LEHO to the domain the browser expects.
  820. *
  821. * @param buffer curl buffer with a single line of header data; not 0-terminated!
  822. * @param size curl blocksize
  823. * @param nmemb curl blocknumber
  824. * @param cls our `struct Socks5Request *`
  825. * @return size of processed bytes
  826. */
  827. static size_t
  828. curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls)
  829. {
  830. struct Socks5Request *s5r = cls;
  831. size_t bytes = size * nmemb;
  832. char *ndup;
  833. const char *hdr_type;
  834. const char *cookie_domain;
  835. char *hdr_val;
  836. long resp_code;
  837. char *new_cookie_hdr;
  838. char *new_location;
  839. size_t offset;
  840. size_t delta_cdomain;
  841. int domain_matched;
  842. char *tok;
  843. if (NULL == s5r->response)
  844. {
  845. /* first, check SSL certificate */
  846. if ( (HTTPS_PORT == s5r->port) &&
  847. (GNUNET_OK != check_ssl_certificate (s5r)) )
  848. return 0;
  849. GNUNET_break (CURLE_OK ==
  850. curl_easy_getinfo (s5r->curl,
  851. CURLINFO_RESPONSE_CODE,
  852. &resp_code));
  853. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  854. "Creating MHD response with code %d\n",
  855. (int) resp_code);
  856. s5r->response_code = resp_code;
  857. s5r->response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
  858. IO_BUFFERSIZE,
  859. &mhd_content_cb,
  860. s5r,
  861. NULL);
  862. if (NULL != s5r->leho)
  863. {
  864. char *cors_hdr;
  865. GNUNET_asprintf (&cors_hdr,
  866. (HTTPS_PORT == s5r->port)
  867. ? "https://%s"
  868. : "http://%s",
  869. s5r->leho);
  870. GNUNET_break (MHD_YES ==
  871. MHD_add_response_header (s5r->response,
  872. MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
  873. cors_hdr));
  874. GNUNET_free (cors_hdr);
  875. }
  876. /* force connection to be closed after each request, as we
  877. do not support HTTP pipelining (yet, FIXME!) */
  878. GNUNET_break (MHD_YES ==
  879. MHD_add_response_header (s5r->response,
  880. MHD_HTTP_HEADER_CONNECTION,
  881. "close"));
  882. }
  883. ndup = GNUNET_strndup (buffer, bytes);
  884. hdr_type = strtok (ndup, ":");
  885. if (NULL == hdr_type)
  886. {
  887. GNUNET_free (ndup);
  888. return bytes;
  889. }
  890. hdr_val = strtok (NULL, "");
  891. if (NULL == hdr_val)
  892. {
  893. GNUNET_free (ndup);
  894. return bytes;
  895. }
  896. if (' ' == *hdr_val)
  897. hdr_val++;
  898. /* custom logic for certain header types */
  899. new_cookie_hdr = NULL;
  900. if ( (NULL != s5r->leho) &&
  901. (0 == strcasecmp (hdr_type,
  902. MHD_HTTP_HEADER_SET_COOKIE)) )
  903. {
  904. new_cookie_hdr = GNUNET_malloc (strlen (hdr_val) +
  905. strlen (s5r->domain) + 1);
  906. offset = 0;
  907. domain_matched = GNUNET_NO; /* make sure we match domain at most once */
  908. for (tok = strtok (hdr_val, ";"); NULL != tok; tok = strtok (NULL, ";"))
  909. {
  910. if ( (0 == strncasecmp (tok, " domain", strlen (" domain"))) &&
  911. (GNUNET_NO == domain_matched) )
  912. {
  913. domain_matched = GNUNET_YES;
  914. cookie_domain = tok + strlen (" domain") + 1;
  915. if (strlen (cookie_domain) < strlen (s5r->leho))
  916. {
  917. delta_cdomain = strlen (s5r->leho) - strlen (cookie_domain);
  918. if (0 == strcasecmp (cookie_domain, s5r->leho + delta_cdomain))
  919. {
  920. offset += sprintf (new_cookie_hdr + offset,
  921. " domain=%s;",
  922. s5r->domain);
  923. continue;
  924. }
  925. }
  926. else if (0 == strcmp (cookie_domain, s5r->leho))
  927. {
  928. offset += sprintf (new_cookie_hdr + offset,
  929. " domain=%s;",
  930. s5r->domain);
  931. continue;
  932. }
  933. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  934. _("Cookie domain `%s' supplied by server is invalid\n"),
  935. tok);
  936. }
  937. memcpy (new_cookie_hdr + offset, tok, strlen (tok));
  938. offset += strlen (tok);
  939. new_cookie_hdr[offset++] = ';';
  940. }
  941. hdr_val = new_cookie_hdr;
  942. }
  943. new_location = NULL;
  944. if (0 == strcasecmp (MHD_HTTP_HEADER_LOCATION, hdr_type))
  945. {
  946. char *leho_host;
  947. GNUNET_asprintf (&leho_host,
  948. (HTTPS_PORT != s5r->port)
  949. ? "http://%s"
  950. : "https://%s",
  951. s5r->leho);
  952. if (0 == strncmp (leho_host,
  953. hdr_val,
  954. strlen (leho_host)))
  955. {
  956. GNUNET_asprintf (&new_location,
  957. "%s%s%s",
  958. (HTTPS_PORT != s5r->port)
  959. ? "http://"
  960. : "https://",
  961. s5r->domain,
  962. hdr_val + strlen (leho_host));
  963. hdr_val = new_location;
  964. }
  965. GNUNET_free (leho_host);
  966. }
  967. /* MHD does not allow certain characters in values, remove those */
  968. if (NULL != (tok = strchr (hdr_val, '\n')))
  969. *tok = '\0';
  970. if (NULL != (tok = strchr (hdr_val, '\r')))
  971. *tok = '\0';
  972. if (NULL != (tok = strchr (hdr_val, '\t')))
  973. *tok = '\0';
  974. if (0 != strlen (hdr_val))
  975. {
  976. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  977. "Adding header %s: %s to MHD response\n",
  978. hdr_type,
  979. hdr_val);
  980. GNUNET_break (MHD_YES ==
  981. MHD_add_response_header (s5r->response,
  982. hdr_type,
  983. hdr_val));
  984. }
  985. GNUNET_free (ndup);
  986. GNUNET_free_non_null (new_cookie_hdr);
  987. GNUNET_free_non_null (new_location);
  988. return bytes;
  989. }
  990. /**
  991. * Handle response payload data from cURL. Copies it into our `io_buf` to make
  992. * it available to MHD.
  993. *
  994. * @param ptr pointer to the data
  995. * @param size number of blocks of data
  996. * @param nmemb blocksize
  997. * @param ctx our `struct Socks5Request *`
  998. * @return number of bytes handled
  999. */
  1000. static size_t
  1001. curl_download_cb (void *ptr, size_t size, size_t nmemb, void* ctx)
  1002. {
  1003. struct Socks5Request *s5r = ctx;
  1004. size_t total = size * nmemb;
  1005. if ( (SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state) ||
  1006. (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state) )
  1007. {
  1008. /* we're still not done with the upload, do not yet
  1009. start the download, the IO buffer is still full
  1010. with upload data. */
  1011. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1012. "Pausing CURL download, waiting for UPLOAD to finish\n");
  1013. return CURL_WRITEFUNC_PAUSE; /* not yet ready for data download */
  1014. }
  1015. if (sizeof (s5r->io_buf) - s5r->io_len < total)
  1016. {
  1017. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1018. "Pausing CURL download, not enough space\n");
  1019. return CURL_WRITEFUNC_PAUSE; /* not enough space */
  1020. }
  1021. memcpy (&s5r->io_buf[s5r->io_len],
  1022. ptr,
  1023. total);
  1024. s5r->io_len += total;
  1025. if (s5r->io_len == total)
  1026. run_mhd_now (s5r->hd);
  1027. return total;
  1028. }
  1029. /**
  1030. * cURL callback for uploaded (PUT/POST) data. Copies it into our `io_buf`
  1031. * to make it available to MHD.
  1032. *
  1033. * @param buf where to write the data
  1034. * @param size number of bytes per member
  1035. * @param nmemb number of members available in @a buf
  1036. * @param cls our `struct Socks5Request` that generated the data
  1037. * @return number of bytes copied to @a buf
  1038. */
  1039. static size_t
  1040. curl_upload_cb (void *buf, size_t size, size_t nmemb, void *cls)
  1041. {
  1042. struct Socks5Request *s5r = cls;
  1043. size_t len = size * nmemb;
  1044. size_t to_copy;
  1045. if ( (0 == s5r->io_len) &&
  1046. (SOCKS5_SOCKET_UPLOAD_DONE != s5r->state) )
  1047. {
  1048. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1049. "Pausing CURL UPLOAD, need more data\n");
  1050. return CURL_READFUNC_PAUSE;
  1051. }
  1052. if ( (0 == s5r->io_len) &&
  1053. (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state) )
  1054. {
  1055. s5r->state = SOCKS5_SOCKET_DOWNLOAD_STARTED;
  1056. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1057. "Completed CURL UPLOAD\n");
  1058. return 0; /* upload finished, can now download */
  1059. }
  1060. if ( (SOCKS5_SOCKET_UPLOAD_STARTED != s5r->state) ||
  1061. (SOCKS5_SOCKET_UPLOAD_DONE != s5r->state) )
  1062. {
  1063. GNUNET_break (0);
  1064. return CURL_READFUNC_ABORT;
  1065. }
  1066. to_copy = GNUNET_MIN (s5r->io_len,
  1067. len);
  1068. memcpy (buf, s5r->io_buf, to_copy);
  1069. memmove (s5r->io_buf,
  1070. &s5r->io_buf[to_copy],
  1071. s5r->io_len - to_copy);
  1072. s5r->io_len -= to_copy;
  1073. if (s5r->io_len + to_copy == sizeof (s5r->io_buf))
  1074. run_mhd_now (s5r->hd); /* got more space for upload now */
  1075. return to_copy;
  1076. }
  1077. /* ************************** main loop of cURL interaction ****************** */
  1078. /**
  1079. * Task that is run when we are ready to receive more data
  1080. * from curl
  1081. *
  1082. * @param cls closure
  1083. * @param tc task context
  1084. */
  1085. static void
  1086. curl_task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
  1087. /**
  1088. * Ask cURL for the select() sets and schedule cURL operations.
  1089. */
  1090. static void
  1091. curl_download_prepare ()
  1092. {
  1093. CURLMcode mret;
  1094. fd_set rs;
  1095. fd_set ws;
  1096. fd_set es;
  1097. int max;
  1098. struct GNUNET_NETWORK_FDSet *grs;
  1099. struct GNUNET_NETWORK_FDSet *gws;
  1100. long to;
  1101. struct GNUNET_TIME_Relative rtime;
  1102. if (NULL != curl_download_task)
  1103. {
  1104. GNUNET_SCHEDULER_cancel (curl_download_task);
  1105. curl_download_task = NULL;
  1106. }
  1107. max = -1;
  1108. FD_ZERO (&rs);
  1109. FD_ZERO (&ws);
  1110. FD_ZERO (&es);
  1111. if (CURLM_OK != (mret = curl_multi_fdset (curl_multi, &rs, &ws, &es, &max)))
  1112. {
  1113. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  1114. "%s failed at %s:%d: `%s'\n",
  1115. "curl_multi_fdset", __FILE__, __LINE__,
  1116. curl_multi_strerror (mret));
  1117. return;
  1118. }
  1119. to = -1;
  1120. GNUNET_break (CURLM_OK == curl_multi_timeout (curl_multi, &to));
  1121. if (-1 == to)
  1122. rtime = GNUNET_TIME_UNIT_FOREVER_REL;
  1123. else
  1124. rtime = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, to);
  1125. if (-1 != max)
  1126. {
  1127. grs = GNUNET_NETWORK_fdset_create ();
  1128. gws = GNUNET_NETWORK_fdset_create ();
  1129. GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
  1130. GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
  1131. curl_download_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
  1132. rtime,
  1133. grs, gws,
  1134. &curl_task_download, curl_multi);
  1135. GNUNET_NETWORK_fdset_destroy (gws);
  1136. GNUNET_NETWORK_fdset_destroy (grs);
  1137. }
  1138. else
  1139. {
  1140. curl_download_task = GNUNET_SCHEDULER_add_delayed (rtime,
  1141. &curl_task_download,
  1142. curl_multi);
  1143. }
  1144. }
  1145. /**
  1146. * Task that is run when we are ready to receive more data from curl.
  1147. *
  1148. * @param cls closure, NULL
  1149. * @param tc task context
  1150. */
  1151. static void
  1152. curl_task_download (void *cls,
  1153. const struct GNUNET_SCHEDULER_TaskContext *tc)
  1154. {
  1155. int running;
  1156. int msgnum;
  1157. struct CURLMsg *msg;
  1158. CURLMcode mret;
  1159. struct Socks5Request *s5r;
  1160. curl_download_task = NULL;
  1161. do
  1162. {
  1163. running = 0;
  1164. mret = curl_multi_perform (curl_multi, &running);
  1165. while (NULL != (msg = curl_multi_info_read (curl_multi, &msgnum)))
  1166. {
  1167. GNUNET_break (CURLE_OK ==
  1168. curl_easy_getinfo (msg->easy_handle,
  1169. CURLINFO_PRIVATE,
  1170. (char **) &s5r ));
  1171. if (NULL == s5r)
  1172. {
  1173. GNUNET_break (0);
  1174. continue;
  1175. }
  1176. switch (msg->msg)
  1177. {
  1178. case CURLMSG_NONE:
  1179. /* documentation says this is not used */
  1180. GNUNET_break (0);
  1181. break;
  1182. case CURLMSG_DONE:
  1183. switch (msg->data.result)
  1184. {
  1185. case CURLE_OK:
  1186. case CURLE_GOT_NOTHING:
  1187. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1188. "CURL download completed.\n");
  1189. s5r->state = SOCKS5_SOCKET_DOWNLOAD_DONE;
  1190. run_mhd_now (s5r->hd);
  1191. break;
  1192. default:
  1193. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  1194. "Download curl failed: %s\n",
  1195. curl_easy_strerror (msg->data.result));
  1196. /* FIXME: indicate error somehow? close MHD connection badly as well? */
  1197. s5r->state = SOCKS5_SOCKET_DOWNLOAD_DONE;
  1198. run_mhd_now (s5r->hd);
  1199. break;
  1200. }
  1201. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1202. "Cleaning up cURL handle\n");
  1203. curl_multi_remove_handle (curl_multi, s5r->curl);
  1204. curl_easy_cleanup (s5r->curl);
  1205. s5r->curl = NULL;
  1206. if (NULL == s5r->response)
  1207. s5r->response = curl_failure_response;
  1208. break;
  1209. case CURLMSG_LAST:
  1210. /* documentation says this is not used */
  1211. GNUNET_break (0);
  1212. break;
  1213. default:
  1214. /* unexpected status code */
  1215. GNUNET_break (0);
  1216. break;
  1217. }
  1218. };
  1219. } while (mret == CURLM_CALL_MULTI_PERFORM);
  1220. if (CURLM_OK != mret)
  1221. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  1222. "%s failed at %s:%d: `%s'\n",
  1223. "curl_multi_perform", __FILE__, __LINE__,
  1224. curl_multi_strerror (mret));
  1225. if (0 == running)
  1226. {
  1227. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1228. "Suspending cURL multi loop, no more events pending\n");
  1229. return; /* nothing more in progress */
  1230. }
  1231. curl_download_prepare ();
  1232. }
  1233. /* ********************************* MHD response generation ******************* */
  1234. /**
  1235. * Read HTTP request header field from the request. Copies the fields
  1236. * over to the 'headers' that will be given to curl. However, 'Host'
  1237. * is substituted with the LEHO if present. We also change the
  1238. * 'Connection' header value to "close" as the proxy does not support
  1239. * pipelining.
  1240. *
  1241. * @param cls our `struct Socks5Request`
  1242. * @param kind value kind
  1243. * @param key field key
  1244. * @param value field value
  1245. * @return MHD_YES to continue to iterate
  1246. */
  1247. static int
  1248. con_val_iter (void *cls,
  1249. enum MHD_ValueKind kind,
  1250. const char *key,
  1251. const char *value)
  1252. {
  1253. struct Socks5Request *s5r = cls;
  1254. char *hdr;
  1255. if ( (0 == strcasecmp (MHD_HTTP_HEADER_HOST, key)) &&
  1256. (NULL != s5r->leho) )
  1257. value = s5r->leho;
  1258. if (0 == strcasecmp (MHD_HTTP_HEADER_CONNECTION, key))
  1259. value = "Close";
  1260. GNUNET_asprintf (&hdr,
  1261. "%s: %s",
  1262. key,
  1263. value);
  1264. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1265. "Adding HEADER `%s' to HTTP request\n",
  1266. hdr);
  1267. s5r->headers = curl_slist_append (s5r->headers,
  1268. hdr);
  1269. GNUNET_free (hdr);
  1270. return MHD_YES;
  1271. }
  1272. /**
  1273. * Main MHD callback for handling requests.
  1274. *
  1275. * @param cls unused
  1276. * @param con MHD connection handle
  1277. * @param url the url in the request
  1278. * @param meth the HTTP method used ("GET", "PUT", etc.)
  1279. * @param ver the HTTP version string (i.e. "HTTP/1.1")
  1280. * @param upload_data the data being uploaded (excluding HEADERS,
  1281. * for a POST that fits into memory and that is encoded
  1282. * with a supported encoding, the POST data will NOT be
  1283. * given in upload_data and is instead available as
  1284. * part of MHD_get_connection_values; very large POST
  1285. * data *will* be made available incrementally in
  1286. * upload_data)
  1287. * @param upload_data_size set initially to the size of the
  1288. * @a upload_data provided; the method must update this
  1289. * value to the number of bytes NOT processed;
  1290. * @param con_cls pointer to location where we store the 'struct Request'
  1291. * @return MHD_YES if the connection was handled successfully,
  1292. * MHD_NO if the socket must be closed due to a serious
  1293. * error while handling the request
  1294. */
  1295. static int
  1296. create_response (void *cls,
  1297. struct MHD_Connection *con,
  1298. const char *url,
  1299. const char *meth,
  1300. const char *ver,
  1301. const char *upload_data,
  1302. size_t *upload_data_size,
  1303. void **con_cls)
  1304. {
  1305. struct Socks5Request *s5r = *con_cls;
  1306. char *curlurl;
  1307. char *curl_hosts;
  1308. char ipstring[INET6_ADDRSTRLEN];
  1309. char ipaddr[INET6_ADDRSTRLEN + 2];
  1310. const struct sockaddr *sa;
  1311. const struct sockaddr_in *s4;
  1312. const struct sockaddr_in6 *s6;
  1313. uint16_t port;
  1314. size_t left;
  1315. if (NULL == s5r)
  1316. {
  1317. GNUNET_break (0);
  1318. return MHD_NO;
  1319. }
  1320. if ( (NULL == s5r->curl) &&
  1321. (SOCKS5_SOCKET_WITH_MHD == s5r->state) )
  1322. {
  1323. /* first time here, initialize curl handle */
  1324. sa = (const struct sockaddr *) &s5r->destination_address;
  1325. switch (sa->sa_family)
  1326. {
  1327. case AF_INET:
  1328. s4 = (const struct sockaddr_in *) &s5r->destination_address;
  1329. if (NULL == inet_ntop (AF_INET,
  1330. &s4->sin_addr,
  1331. ipstring,
  1332. sizeof (ipstring)))
  1333. {
  1334. GNUNET_break (0);
  1335. return MHD_NO;
  1336. }
  1337. GNUNET_snprintf (ipaddr,
  1338. sizeof (ipaddr),
  1339. "%s",
  1340. ipstring);
  1341. port = ntohs (s4->sin_port);
  1342. break;
  1343. case AF_INET6:
  1344. s6 = (const struct sockaddr_in6 *) &s5r->destination_address;
  1345. if (NULL == inet_ntop (AF_INET6,
  1346. &s6->sin6_addr,
  1347. ipstring,
  1348. sizeof (ipstring)))
  1349. {
  1350. GNUNET_break (0);
  1351. return MHD_NO;
  1352. }
  1353. GNUNET_snprintf (ipaddr,
  1354. sizeof (ipaddr),
  1355. "[%s]",
  1356. ipstring);
  1357. port = ntohs (s6->sin6_port);
  1358. break;
  1359. default:
  1360. GNUNET_break (0);
  1361. return MHD_NO;
  1362. }
  1363. s5r->curl = curl_easy_init ();
  1364. if (NULL == s5r->curl)
  1365. return MHD_queue_response (con,
  1366. MHD_HTTP_INTERNAL_SERVER_ERROR,
  1367. curl_failure_response);
  1368. curl_easy_setopt (s5r->curl, CURLOPT_HEADERFUNCTION, &curl_check_hdr);
  1369. curl_easy_setopt (s5r->curl, CURLOPT_HEADERDATA, s5r);
  1370. curl_easy_setopt (s5r->curl, CURLOPT_FOLLOWLOCATION, 0);
  1371. curl_easy_setopt (s5r->curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
  1372. curl_easy_setopt (s5r->curl, CURLOPT_CONNECTTIMEOUT, 600L);
  1373. curl_easy_setopt (s5r->curl, CURLOPT_TIMEOUT, 600L);
  1374. curl_easy_setopt (s5r->curl, CURLOPT_NOSIGNAL, 1L);
  1375. curl_easy_setopt (s5r->curl, CURLOPT_HTTP_CONTENT_DECODING, 0);
  1376. curl_easy_setopt (s5r->curl, CURLOPT_HTTP_TRANSFER_DECODING, 0);
  1377. curl_easy_setopt (s5r->curl, CURLOPT_NOSIGNAL, 1L);
  1378. curl_easy_setopt (s5r->curl, CURLOPT_PRIVATE, s5r);
  1379. curl_easy_setopt (s5r->curl, CURLOPT_VERBOSE, 0);
  1380. /**
  1381. * Pre-populate cache to resolve Hostname.
  1382. * This is necessary as the DNS name in the CURLOPT_URL is used
  1383. * for SNI http://de.wikipedia.org/wiki/Server_Name_Indication
  1384. */
  1385. if (NULL != s5r->leho)
  1386. {
  1387. GNUNET_asprintf (&curl_hosts,
  1388. "%s:%d:%s",
  1389. s5r->leho,
  1390. port,
  1391. ipaddr);
  1392. s5r->hosts = curl_slist_append(NULL, curl_hosts);
  1393. curl_easy_setopt(s5r->curl, CURLOPT_RESOLVE, s5r->hosts);
  1394. GNUNET_free (curl_hosts);
  1395. }
  1396. GNUNET_asprintf (&curlurl,
  1397. (HTTPS_PORT != s5r->port)
  1398. ? "http://%s:%d%s"
  1399. : "https://%s:%d%s",
  1400. (NULL != s5r->leho)
  1401. ? s5r->leho
  1402. : ipaddr,
  1403. port,
  1404. s5r->url);
  1405. curl_easy_setopt (s5r->curl,
  1406. CURLOPT_URL,
  1407. curlurl);
  1408. GNUNET_free (curlurl);
  1409. if (0 == strcasecmp (meth, MHD_HTTP_METHOD_PUT))
  1410. {
  1411. s5r->state = SOCKS5_SOCKET_UPLOAD_STARTED;
  1412. curl_easy_setopt (s5r->curl, CURLOPT_UPLOAD, 1);
  1413. curl_easy_setopt (s5r->curl, CURLOPT_WRITEFUNCTION, &curl_download_cb);
  1414. curl_easy_setopt (s5r->curl, CURLOPT_WRITEDATA, s5r);
  1415. curl_easy_setopt (s5r->curl, CURLOPT_READFUNCTION, &curl_upload_cb);
  1416. curl_easy_setopt (s5r->curl, CURLOPT_READDATA, s5r);
  1417. }
  1418. else if (0 == strcasecmp (meth, MHD_HTTP_METHOD_POST))
  1419. {
  1420. s5r->state = SOCKS5_SOCKET_UPLOAD_STARTED;
  1421. curl_easy_setopt (s5r->curl, CURLOPT_POST, 1);
  1422. curl_easy_setopt (s5r->curl, CURLOPT_WRITEFUNCTION, &curl_download_cb);
  1423. curl_easy_setopt (s5r->curl, CURLOPT_WRITEDATA, s5r);
  1424. curl_easy_setopt (s5r->curl, CURLOPT_READFUNCTION, &curl_upload_cb);
  1425. curl_easy_setopt (s5r->curl, CURLOPT_READDATA, s5r);
  1426. }
  1427. else if (0 == strcasecmp (meth, MHD_HTTP_METHOD_HEAD))
  1428. {
  1429. s5r->state = SOCKS5_SOCKET_DOWNLOAD_STARTED;
  1430. curl_easy_setopt (s5r->curl, CURLOPT_NOBODY, 1);
  1431. }
  1432. else if (0 == strcasecmp (meth, MHD_HTTP_METHOD_GET))
  1433. {
  1434. s5r->state = SOCKS5_SOCKET_DOWNLOAD_STARTED;
  1435. curl_easy_setopt (s5r->curl, CURLOPT_HTTPGET, 1);
  1436. curl_easy_setopt (s5r->curl, CURLOPT_WRITEFUNCTION, &curl_download_cb);
  1437. curl_easy_setopt (s5r->curl, CURLOPT_WRITEDATA, s5r);
  1438. }
  1439. else
  1440. {
  1441. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  1442. _("Unsupported HTTP method `%s'\n"),
  1443. meth);
  1444. curl_easy_cleanup (s5r->curl);
  1445. s5r->curl = NULL;
  1446. return MHD_NO;
  1447. }
  1448. if (0 == strcasecmp (ver, MHD_HTTP_VERSION_1_0))
  1449. {
  1450. curl_easy_setopt (s5r->curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
  1451. }
  1452. else if (0 == strcasecmp (ver, MHD_HTTP_VERSION_1_1))
  1453. {
  1454. curl_easy_setopt (s5r->curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
  1455. }
  1456. else
  1457. {
  1458. curl_easy_setopt (s5r->curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_NONE);
  1459. }
  1460. if (HTTPS_PORT == s5r->port)
  1461. {
  1462. curl_easy_setopt (s5r->curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
  1463. curl_easy_setopt (s5r->curl, CURLOPT_SSL_VERIFYPEER, 1L);
  1464. /* Disable cURL checking the hostname, as we will check ourselves
  1465. as only we have the domain name or the LEHO or the DANE record */
  1466. curl_easy_setopt (s5r->curl, CURLOPT_SSL_VERIFYHOST, 0L);
  1467. }
  1468. else
  1469. {
  1470. curl_easy_setopt (s5r->curl, CURLOPT_USE_SSL, CURLUSESSL_NONE);
  1471. }
  1472. if (CURLM_OK != curl_multi_add_handle (curl_multi, s5r->curl))
  1473. {
  1474. GNUNET_break (0);
  1475. curl_easy_cleanup (s5r->curl);
  1476. s5r->curl = NULL;
  1477. return MHD_NO;
  1478. }
  1479. MHD_get_connection_values (con,
  1480. MHD_HEADER_KIND,
  1481. &con_val_iter, s5r);
  1482. curl_easy_setopt (s5r->curl, CURLOPT_HTTPHEADER, s5r->headers);
  1483. curl_download_prepare ();
  1484. return MHD_YES;
  1485. }
  1486. /* continuing to process request */
  1487. if (0 != *upload_data_size)
  1488. {
  1489. left = GNUNET_MIN (*upload_data_size,
  1490. sizeof (s5r->io_buf) - s5r->io_len);
  1491. memcpy (&s5r->io_buf[s5r->io_len],
  1492. upload_data,
  1493. left);
  1494. s5r->io_len += left;
  1495. *upload_data_size -= left;
  1496. GNUNET_assert (NULL != s5r->curl);
  1497. curl_easy_pause (s5r->curl, CURLPAUSE_CONT);
  1498. curl_download_prepare ();
  1499. return MHD_YES;
  1500. }
  1501. if (SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state)
  1502. {
  1503. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1504. "Finished processing UPLOAD\n");
  1505. s5r->state = SOCKS5_SOCKET_UPLOAD_DONE;
  1506. }
  1507. if (NULL == s5r->response)
  1508. return MHD_YES; /* too early to queue response, did not yet get headers from cURL */
  1509. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1510. "Queueing response with MHD\n");
  1511. return MHD_queue_response (con,
  1512. s5r->response_code,
  1513. s5r->response);
  1514. }
  1515. /* ******************** MHD HTTP setup and event loop ******************** */
  1516. /**
  1517. * Function called when MHD decides that we are done with a connection.
  1518. *
  1519. * @param cls NULL
  1520. * @param connection connection handle
  1521. * @param con_cls value as set by the last call to
  1522. * the MHD_AccessHandlerCallback, should be our `struct Socks5Request *`
  1523. * @param toe reason for request termination (ignored)
  1524. */
  1525. static void
  1526. mhd_completed_cb (void *cls,
  1527. struct MHD_Connection *connection,
  1528. void **con_cls,
  1529. enum MHD_RequestTerminationCode toe)
  1530. {
  1531. struct Socks5Request *s5r = *con_cls;
  1532. if (NULL == s5r)
  1533. return;
  1534. if (MHD_REQUEST_TERMINATED_COMPLETED_OK != toe)
  1535. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  1536. "MHD encountered error handling request: %d\n",
  1537. toe);
  1538. cleanup_s5r (s5r);
  1539. curl_download_prepare();
  1540. *con_cls = NULL;
  1541. }
  1542. /**
  1543. * Function called when MHD first processes an incoming connection.
  1544. * Gives us the respective URI information.
  1545. *
  1546. * We use this to associate the `struct MHD_Connection` with our
  1547. * internal `struct Socks5Request` data structure (by checking
  1548. * for matching sockets).
  1549. *
  1550. * @param cls the HTTP server handle (a `struct MhdHttpList`)
  1551. * @param url the URL that is being requested
  1552. * @param connection MHD connection object for the request
  1553. * @return the `struct Socks5Request` that this @a connection is for
  1554. */
  1555. static void *
  1556. mhd_log_callback (void *cls,
  1557. const char *url,
  1558. struct MHD_Connection *connection)
  1559. {
  1560. struct Socks5Request *s5r;
  1561. const union MHD_ConnectionInfo *ci;
  1562. int sock;
  1563. ci = MHD_get_connection_info (connection,
  1564. MHD_CONNECTION_INFO_CONNECTION_FD);
  1565. if (NULL == ci)
  1566. {
  1567. GNUNET_break (0);
  1568. return NULL;
  1569. }
  1570. sock = ci->connect_fd;
  1571. for (s5r = s5r_head; NULL != s5r; s5r = s5r->next)
  1572. {
  1573. if (GNUNET_NETWORK_get_fd (s5r->sock) == sock)
  1574. {
  1575. if (NULL != s5r->url)
  1576. {
  1577. GNUNET_break (0);
  1578. return NULL;
  1579. }
  1580. s5r->url = GNUNET_strdup (url);
  1581. GNUNET_SCHEDULER_cancel (s5r->timeout_task);
  1582. s5r->timeout_task = NULL;
  1583. return s5r;
  1584. }
  1585. }
  1586. GNUNET_break (0);
  1587. return NULL;
  1588. }
  1589. /**
  1590. * Kill the given MHD daemon.
  1591. *
  1592. * @param hd daemon to stop
  1593. */
  1594. static void
  1595. kill_httpd (struct MhdHttpList *hd)
  1596. {
  1597. GNUNET_CONTAINER_DLL_remove (mhd_httpd_head,
  1598. mhd_httpd_tail,
  1599. hd);
  1600. GNUNET_free_non_null (hd->domain);
  1601. MHD_stop_daemon (hd->daemon);
  1602. if (NULL != hd->httpd_task)
  1603. {
  1604. GNUNET_SCHEDULER_cancel (hd->httpd_task);
  1605. hd->httpd_task = NULL;
  1606. }
  1607. GNUNET_free_non_null (hd->proxy_cert);
  1608. if (hd == httpd)
  1609. httpd = NULL;
  1610. GNUNET_free (hd);
  1611. }
  1612. /**
  1613. * Task run whenever HTTP server is idle for too long. Kill it.
  1614. *
  1615. * @param cls the `struct MhdHttpList *`
  1616. * @param tc sched context
  1617. */
  1618. static void
  1619. kill_httpd_task (void *cls,
  1620. const struct GNUNET_SCHEDULER_TaskContext *tc)
  1621. {
  1622. struct MhdHttpList *hd = cls;
  1623. hd->httpd_task = NULL;
  1624. kill_httpd (hd);
  1625. }
  1626. /**
  1627. * Task run whenever HTTP server operations are pending.
  1628. *
  1629. * @param cls the `struct MhdHttpList *` of the daemon that is being run
  1630. * @param tc sched context
  1631. */
  1632. static void
  1633. do_httpd (void *cls,
  1634. const struct GNUNET_SCHEDULER_TaskContext *tc);
  1635. /**
  1636. * Schedule MHD. This function should be called initially when an
  1637. * MHD is first getting its client socket, and will then automatically
  1638. * always be called later whenever there is work to be done.
  1639. *
  1640. * @param hd the daemon to schedule
  1641. */
  1642. static void
  1643. schedule_httpd (struct MhdHttpList *hd)
  1644. {
  1645. fd_set rs;
  1646. fd_set ws;
  1647. fd_set es;
  1648. struct GNUNET_NETWORK_FDSet *wrs;
  1649. struct GNUNET_NETWORK_FDSet *wws;
  1650. int max;
  1651. int haveto;
  1652. MHD_UNSIGNED_LONG_LONG timeout;
  1653. struct GNUNET_TIME_Relative tv;
  1654. FD_ZERO (&rs);
  1655. FD_ZERO (&ws);
  1656. FD_ZERO (&es);
  1657. max = -1;
  1658. if (MHD_YES != MHD_get_fdset (hd->daemon, &rs, &ws, &es, &max))
  1659. {
  1660. kill_httpd (hd);
  1661. return;
  1662. }
  1663. haveto = MHD_get_timeout (hd->daemon, &timeout);
  1664. if (MHD_YES == haveto)
  1665. tv.rel_value_us = (uint64_t) timeout * 1000LL;
  1666. else
  1667. tv = GNUNET_TIME_UNIT_FOREVER_REL;
  1668. if (-1 != max)
  1669. {
  1670. wrs = GNUNET_NETWORK_fdset_create ();
  1671. wws = GNUNET_NETWORK_fdset_create ();
  1672. GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
  1673. GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
  1674. }
  1675. else
  1676. {
  1677. wrs = NULL;
  1678. wws = NULL;
  1679. }
  1680. if (NULL != hd->httpd_task)
  1681. GNUNET_SCHEDULER_cancel (hd->httpd_task);
  1682. if ( (MHD_YES != haveto) &&
  1683. (-1 == max) &&
  1684. (hd != httpd) )
  1685. {
  1686. /* daemon is idle, kill after timeout */
  1687. hd->httpd_task = GNUNET_SCHEDULER_add_delayed (MHD_CACHE_TIMEOUT,
  1688. &kill_httpd_task,
  1689. hd);
  1690. }
  1691. else
  1692. {
  1693. hd->httpd_task =
  1694. GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
  1695. tv, wrs, wws,
  1696. &do_httpd, hd);
  1697. }
  1698. if (NULL != wrs)
  1699. GNUNET_NETWORK_fdset_destroy (wrs);
  1700. if (NULL != wws)
  1701. GNUNET_NETWORK_fdset_destroy (wws);
  1702. }
  1703. /**
  1704. * Task run whenever HTTP server operations are pending.
  1705. *
  1706. * @param cls the `struct MhdHttpList` of the daemon that is being run
  1707. * @param tc scheduler context
  1708. */
  1709. static void
  1710. do_httpd (void *cls,
  1711. const struct GNUNET_SCHEDULER_TaskContext *tc)
  1712. {
  1713. struct MhdHttpList *hd = cls;
  1714. hd->httpd_task = NULL;
  1715. MHD_run (hd->daemon);
  1716. schedule_httpd (hd);
  1717. }
  1718. /**
  1719. * Run MHD now, we have extra data ready for the callback.
  1720. *
  1721. * @param hd the daemon to run now.
  1722. */
  1723. static void
  1724. run_mhd_now (struct MhdHttpList *hd)
  1725. {
  1726. if (NULL !=
  1727. hd->httpd_task)
  1728. GNUNET_SCHEDULER_cancel (hd->httpd_task);
  1729. hd->httpd_task = GNUNET_SCHEDULER_add_now (&do_httpd,
  1730. hd);
  1731. }
  1732. /**
  1733. * Read file in filename
  1734. *
  1735. * @param filename file to read
  1736. * @param size pointer where filesize is stored
  1737. * @return NULL on error
  1738. */
  1739. static void*
  1740. load_file (const char* filename,
  1741. unsigned int* size)
  1742. {
  1743. void *buffer;
  1744. uint64_t fsize;
  1745. if (GNUNET_OK !=
  1746. GNUNET_DISK_file_size (filename, &fsize,
  1747. GNUNET_YES, GNUNET_YES))
  1748. return NULL;
  1749. if (fsize > MAX_PEM_SIZE)
  1750. return NULL;
  1751. *size = (unsigned int) fsize;
  1752. buffer = GNUNET_malloc (*size);
  1753. if (fsize != GNUNET_DISK_fn_read (filename, buffer, (size_t) fsize))
  1754. {
  1755. GNUNET_free (buffer);
  1756. return NULL;
  1757. }
  1758. return buffer;
  1759. }
  1760. /**
  1761. * Load PEM key from file
  1762. *
  1763. * @param key where to store the data
  1764. * @param keyfile path to the PEM file
  1765. * @return #GNUNET_OK on success
  1766. */
  1767. static int
  1768. load_key_from_file (gnutls_x509_privkey_t key,
  1769. const char* keyfile)
  1770. {
  1771. gnutls_datum_t key_data;
  1772. int ret;
  1773. key_data.data = load_file (keyfile, &key_data.size);
  1774. if (NULL == key_data.data)
  1775. return GNUNET_SYSERR;
  1776. ret = gnutls_x509_privkey_import (key, &key_data,
  1777. GNUTLS_X509_FMT_PEM);
  1778. if (GNUTLS_E_SUCCESS != ret)
  1779. {
  1780. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  1781. _("Unable to import private key from file `%s'\n"),
  1782. keyfile);
  1783. }
  1784. GNUNET_free_non_null (key_data.data);
  1785. return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK;
  1786. }
  1787. /**
  1788. * Load cert from file
  1789. *
  1790. * @param crt struct to store data in
  1791. * @param certfile path to pem file
  1792. * @return #GNUNET_OK on success
  1793. */
  1794. static int
  1795. load_cert_from_file (gnutls_x509_crt_t crt,
  1796. const char* certfile)
  1797. {
  1798. gnutls_datum_t cert_data;
  1799. int ret;
  1800. cert_data.data = load_file (certfile, &cert_data.size);
  1801. if (NULL == cert_data.data)
  1802. return GNUNET_SYSERR;
  1803. ret = gnutls_x509_crt_import (crt, &cert_data,
  1804. GNUTLS_X509_FMT_PEM);
  1805. if (GNUTLS_E_SUCCESS != ret)
  1806. {
  1807. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  1808. _("Unable to import certificate %s\n"), certfile);
  1809. }
  1810. GNUNET_free_non_null (cert_data.data);
  1811. return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK;
  1812. }
  1813. /**
  1814. * Generate new certificate for specific name
  1815. *
  1816. * @param name the subject name to generate a cert for
  1817. * @return a struct holding the PEM data, NULL on error
  1818. */
  1819. static struct ProxyGNSCertificate *
  1820. generate_gns_certificate (const char *name)
  1821. {
  1822. unsigned int serial;
  1823. size_t key_buf_size;
  1824. size_t cert_buf_size;
  1825. gnutls_x509_crt_t request;
  1826. time_t etime;
  1827. struct tm *tm_data;
  1828. struct ProxyGNSCertificate *pgc;
  1829. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1830. "Generating TLS/SSL certificate for `%s'\n",
  1831. name);
  1832. GNUNET_break (GNUTLS_E_SUCCESS == gnutls_x509_crt_init (&request));
  1833. GNUNET_break (GNUTLS_E_SUCCESS == gnutls_x509_crt_set_key (request, proxy_ca.key));
  1834. pgc = GNUNET_new (struct ProxyGNSCertificate);
  1835. gnutls_x509_crt_set_dn_by_oid (request, GNUTLS_OID_X520_COUNTRY_NAME,
  1836. 0, "ZZ", 2);
  1837. gnutls_x509_crt_set_dn_by_oid (request, GNUTLS_OID_X520_ORGANIZATION_NAME,
  1838. 0, "GNU Name System", 4);
  1839. gnutls_x509_crt_set_dn_by_oid (request, GNUTLS_OID_X520_COMMON_NAME,
  1840. 0, name, strlen (name));
  1841. GNUNET_break (GNUTLS_E_SUCCESS == gnutls_x509_crt_set_version (request, 3));
  1842. gnutls_rnd (GNUTLS_RND_NONCE, &serial, sizeof (serial));
  1843. gnutls_x509_crt_set_serial (request,
  1844. &serial,
  1845. sizeof (serial));
  1846. etime = time (NULL);
  1847. tm_data = localtime (&etime);
  1848. gnutls_x509_crt_set_activation_time (request,
  1849. etime);
  1850. tm_data->tm_year++;
  1851. etime = mktime (tm_data);
  1852. gnutls_x509_crt_set_expiration_time (request,
  1853. etime);
  1854. gnutls_x509_crt_sign (request,
  1855. proxy_ca.cert,
  1856. proxy_ca.key);
  1857. key_buf_size = sizeof (pgc->key);
  1858. cert_buf_size = sizeof (pgc->cert);
  1859. gnutls_x509_crt_export (request, GNUTLS_X509_FMT_PEM,
  1860. pgc->cert, &cert_buf_size);
  1861. gnutls_x509_privkey_export (proxy_ca.key, GNUTLS_X509_FMT_PEM,
  1862. pgc->key, &key_buf_size);
  1863. gnutls_x509_crt_deinit (request);
  1864. return pgc;
  1865. }
  1866. /**
  1867. * Function called by MHD with errors, suppresses them all.
  1868. *
  1869. * @param cls closure
  1870. * @param fm format string (`printf()`-style)
  1871. * @param ap arguments to @a fm
  1872. */
  1873. static void
  1874. mhd_error_log_callback (void *cls,
  1875. const char *fm,
  1876. va_list ap)
  1877. {
  1878. /* do nothing */
  1879. }
  1880. /**
  1881. * Lookup (or create) an SSL MHD instance for a particular domain.
  1882. *
  1883. * @param domain the domain the SSL daemon has to serve
  1884. * @return NULL on error
  1885. */
  1886. static struct MhdHttpList *
  1887. lookup_ssl_httpd (const char* domain)
  1888. {
  1889. struct MhdHttpList *hd;
  1890. struct ProxyGNSCertificate *pgc;
  1891. if (NULL == domain)
  1892. {
  1893. GNUNET_break (0);
  1894. return NULL;
  1895. }
  1896. for (hd = mhd_httpd_head; NULL != hd; hd = hd->next)
  1897. if ( (NULL != hd->domain) &&
  1898. (0 == strcmp (hd->domain, domain)) )
  1899. return hd;
  1900. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1901. "Starting fresh MHD HTTPS instance for domain `%s'\n",
  1902. domain);
  1903. pgc = generate_gns_certificate (domain);
  1904. hd = GNUNET_new (struct MhdHttpList);
  1905. hd->is_ssl = GNUNET_YES;
  1906. hd->domain = GNUNET_strdup (domain);
  1907. hd->proxy_cert = pgc;
  1908. hd->daemon = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_SSL | MHD_USE_NO_LISTEN_SOCKET,
  1909. 0,
  1910. NULL, NULL,
  1911. &create_response, hd,
  1912. MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16,
  1913. MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb, NULL,
  1914. MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback, NULL,
  1915. MHD_OPTION_EXTERNAL_LOGGER, &mhd_error_log_callback, NULL,
  1916. MHD_OPTION_HTTPS_MEM_KEY, pgc->key,
  1917. MHD_OPTION_HTTPS_MEM_CERT, pgc->cert,
  1918. MHD_OPTION_END);
  1919. if (NULL == hd->daemon)
  1920. {
  1921. GNUNET_free (pgc);
  1922. GNUNET_free (hd);
  1923. return NULL;
  1924. }
  1925. GNUNET_CONTAINER_DLL_insert (mhd_httpd_head,
  1926. mhd_httpd_tail,
  1927. hd);
  1928. return hd;
  1929. }
  1930. /**
  1931. * Task run when a Socks5Request somehow fails to be associated with
  1932. * an MHD connection (i.e. because the client never speaks HTTP after
  1933. * the SOCKS5 handshake). Clean up.
  1934. *
  1935. * @param cls the `struct Socks5Request *`
  1936. * @param tc sched context
  1937. */
  1938. static void
  1939. timeout_s5r_handshake (void *cls,
  1940. const struct GNUNET_SCHEDULER_TaskContext *tc)
  1941. {
  1942. struct Socks5Request *s5r = cls;
  1943. s5r->timeout_task = NULL;
  1944. cleanup_s5r (s5r);
  1945. }
  1946. /**
  1947. * We're done with the Socks5 protocol, now we need to pass the
  1948. * connection data through to the final destination, either
  1949. * direct (if the protocol might not be HTTP), or via MHD
  1950. * (if the port looks like it should be HTTP).
  1951. *
  1952. * @param s5r socks request that has reached the final stage
  1953. */
  1954. static void
  1955. setup_data_transfer (struct Socks5Request *s5r)
  1956. {
  1957. struct MhdHttpList *hd;
  1958. int fd;
  1959. const struct sockaddr *addr;
  1960. socklen_t len;
  1961. switch (s5r->port)
  1962. {
  1963. case HTTPS_PORT:
  1964. hd = lookup_ssl_httpd (s5r->domain);
  1965. if (NULL == hd)
  1966. {
  1967. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  1968. _("Failed to start HTTPS server for `%s'\n"),
  1969. s5r->domain);
  1970. cleanup_s5r (s5r);
  1971. return;
  1972. }
  1973. break;
  1974. case HTTP_PORT:
  1975. default:
  1976. GNUNET_assert (NULL != httpd);
  1977. hd = httpd;
  1978. break;
  1979. }
  1980. fd = GNUNET_NETWORK_get_fd (s5r->sock);
  1981. addr = GNUNET_NETWORK_get_addr (s5r->sock);
  1982. len = GNUNET_NETWORK_get_addrlen (s5r->sock);
  1983. s5r->state = SOCKS5_SOCKET_WITH_MHD;
  1984. if (MHD_YES != MHD_add_connection (hd->daemon, fd, addr, len))
  1985. {
  1986. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  1987. _("Failed to pass client to MHD\n"));
  1988. cleanup_s5r (s5r);
  1989. return;
  1990. }
  1991. s5r->hd = hd;
  1992. schedule_httpd (hd);
  1993. s5r->timeout_task = GNUNET_SCHEDULER_add_delayed (HTTP_HANDSHAKE_TIMEOUT,
  1994. &timeout_s5r_handshake,
  1995. s5r);
  1996. }
  1997. /* ********************* SOCKS handling ************************* */
  1998. /**
  1999. * Write data from buffer to socks5 client, then continue with state machine.
  2000. *
  2001. * @param cls the closure with the `struct Socks5Request`
  2002. * @param tc scheduler context
  2003. */
  2004. static void
  2005. do_write (void *cls,
  2006. const struct GNUNET_SCHEDULER_TaskContext *tc)
  2007. {
  2008. struct Socks5Request *s5r = cls;
  2009. ssize_t len;
  2010. s5r->wtask = NULL;
  2011. len = GNUNET_NETWORK_socket_send (s5r->sock,
  2012. s5r->wbuf,
  2013. s5r->wbuf_len);
  2014. if (len <= 0)
  2015. {
  2016. /* write error: connection closed, shutdown, etc.; just clean up */
  2017. cleanup_s5r (s5r);
  2018. return;
  2019. }
  2020. memmove (s5r->wbuf,
  2021. &s5r->wbuf[len],
  2022. s5r->wbuf_len - len);
  2023. s5r->wbuf_len -= len;
  2024. if (s5r->wbuf_len > 0)
  2025. {
  2026. /* not done writing */
  2027. s5r->wtask =
  2028. GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
  2029. s5r->sock,
  2030. &do_write, s5r);
  2031. return;
  2032. }
  2033. /* we're done writing, continue with state machine! */
  2034. switch (s5r->state)
  2035. {
  2036. case SOCKS5_INIT:
  2037. GNUNET_assert (0);
  2038. break;
  2039. case SOCKS5_REQUEST:
  2040. GNUNET_assert (NULL != s5r->rtask);
  2041. break;
  2042. case SOCKS5_DATA_TRANSFER:
  2043. setup_data_transfer (s5r);
  2044. return;
  2045. case SOCKS5_WRITE_THEN_CLEANUP:
  2046. cleanup_s5r (s5r);
  2047. return;
  2048. default:
  2049. GNUNET_break (0);
  2050. break;
  2051. }
  2052. }
  2053. /**
  2054. * Return a server response message indicating a failure to the client.
  2055. *
  2056. * @param s5r request to return failure code for
  2057. * @param sc status code to return
  2058. */
  2059. static void
  2060. signal_socks_failure (struct Socks5Request *s5r,
  2061. enum Socks5StatusCode sc)
  2062. {
  2063. struct Socks5ServerResponseMessage *s_resp;
  2064. s_resp = (struct Socks5ServerResponseMessage *) &s5r->wbuf[s5r->wbuf_len];
  2065. memset (s_resp, 0, sizeof (struct Socks5ServerResponseMessage));
  2066. s_resp->version = SOCKS_VERSION_5;
  2067. s_resp->reply = sc;
  2068. s5r->state = SOCKS5_WRITE_THEN_CLEANUP;
  2069. if (NULL != s5r->wtask)
  2070. s5r->wtask =
  2071. GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
  2072. s5r->sock,
  2073. &do_write, s5r);
  2074. }
  2075. /**
  2076. * Return a server response message indicating success.
  2077. *
  2078. * @param s5r request to return success status message for
  2079. */
  2080. static void
  2081. signal_socks_success (struct Socks5Request *s5r)
  2082. {
  2083. struct Socks5ServerResponseMessage *s_resp;
  2084. s_resp = (struct Socks5ServerResponseMessage *) &s5r->wbuf[s5r->wbuf_len];
  2085. s_resp->version = SOCKS_VERSION_5;
  2086. s_resp->reply = SOCKS5_STATUS_REQUEST_GRANTED;
  2087. s_resp->reserved = 0;
  2088. s_resp->addr_type = SOCKS5_AT_IPV4;
  2089. /* zero out IPv4 address and port */
  2090. memset (&s_resp[1],
  2091. 0,
  2092. sizeof (struct in_addr) + sizeof (uint16_t));
  2093. s5r->wbuf_len += sizeof (struct Socks5ServerResponseMessage) +
  2094. sizeof (struct in_addr) + sizeof (uint16_t);
  2095. if (NULL == s5r->wtask)
  2096. s5r->wtask =
  2097. GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
  2098. s5r->sock,
  2099. &do_write, s5r);
  2100. }
  2101. /**
  2102. * Process GNS results for target domain.
  2103. *
  2104. * @param cls the `struct Socks5Request *`
  2105. * @param rd_count number of records returned
  2106. * @param rd record data
  2107. */
  2108. static void
  2109. handle_gns_result (void *cls,
  2110. uint32_t rd_count,
  2111. const struct GNUNET_GNSRECORD_Data *rd)
  2112. {
  2113. struct Socks5Request *s5r = cls;
  2114. uint32_t i;
  2115. const struct GNUNET_GNSRECORD_Data *r;
  2116. int got_ip;
  2117. s5r->gns_lookup = NULL;
  2118. got_ip = GNUNET_NO;
  2119. for (i=0;i<rd_count;i++)
  2120. {
  2121. r = &rd[i];
  2122. switch (r->record_type)
  2123. {
  2124. case GNUNET_DNSPARSER_TYPE_A:
  2125. {
  2126. struct sockaddr_in *in;
  2127. if (sizeof (struct in_addr) != r->data_size)
  2128. {
  2129. GNUNET_break_op (0);
  2130. break;
  2131. }
  2132. if (GNUNET_YES == got_ip)
  2133. break;
  2134. if (GNUNET_OK !=
  2135. GNUNET_NETWORK_test_pf (PF_INET))
  2136. break;
  2137. got_ip = GNUNET_YES;
  2138. in = (struct sockaddr_in *) &s5r->destination_address;
  2139. in->sin_family = AF_INET;
  2140. memcpy (&in->sin_addr,
  2141. r->data,
  2142. r->data_size);
  2143. in->sin_port = htons (s5r->port);
  2144. #if HAVE_SOCKADDR_IN_SIN_LEN
  2145. in->sin_len = sizeof (*in);
  2146. #endif
  2147. }
  2148. break;
  2149. case GNUNET_DNSPARSER_TYPE_AAAA:
  2150. {
  2151. struct sockaddr_in6 *in;
  2152. if (sizeof (struct in6_addr) != r->data_size)
  2153. {
  2154. GNUNET_break_op (0);
  2155. break;
  2156. }
  2157. if (GNUNET_YES == got_ip)
  2158. break;
  2159. if (GNUNET_OK !=
  2160. GNUNET_NETWORK_test_pf (PF_INET))
  2161. break;
  2162. /* FIXME: allow user to disable IPv6 per configuration option... */
  2163. got_ip = GNUNET_YES;
  2164. in = (struct sockaddr_in6 *) &s5r->destination_address;
  2165. in->sin6_family = AF_INET6;
  2166. memcpy (&in->sin6_addr,
  2167. r->data,
  2168. r->data_size);
  2169. in->sin6_port = htons (s5r->port);
  2170. #if HAVE_SOCKADDR_IN_SIN_LEN
  2171. in->sin6_len = sizeof (*in);
  2172. #endif
  2173. }
  2174. break;
  2175. case GNUNET_GNSRECORD_TYPE_VPN:
  2176. GNUNET_break (0); /* should have been translated within GNS */
  2177. break;
  2178. case GNUNET_GNSRECORD_TYPE_LEHO:
  2179. GNUNET_free_non_null (s5r->leho);
  2180. s5r->leho = GNUNET_strndup (r->data,
  2181. r->data_size);
  2182. break;
  2183. case GNUNET_GNSRECORD_TYPE_BOX:
  2184. {
  2185. const struct GNUNET_GNSRECORD_BoxRecord *box;
  2186. if (r->data_size < sizeof (struct GNUNET_GNSRECORD_BoxRecord))
  2187. {
  2188. GNUNET_break_op (0);
  2189. break;
  2190. }
  2191. box = r->data;
  2192. if ( (ntohl (box->record_type) != GNUNET_DNSPARSER_TYPE_TLSA) ||
  2193. (ntohs (box->protocol) != IPPROTO_TCP) ||
  2194. (ntohs (box->service) != s5r->port) )
  2195. break; /* BOX record does not apply */
  2196. GNUNET_free_non_null (s5r->dane_data);
  2197. s5r->dane_data_len = r->data_size - sizeof (struct GNUNET_GNSRECORD_BoxRecord);
  2198. s5r->dane_data = GNUNET_malloc (s5r->dane_data_len);
  2199. memcpy (s5r->dane_data,
  2200. &box[1],
  2201. s5r->dane_data_len);
  2202. break;
  2203. }
  2204. default:
  2205. /* don't care */
  2206. break;
  2207. }
  2208. }
  2209. if (GNUNET_YES != got_ip)
  2210. {
  2211. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2212. "Name resolution failed to yield useful IP address.\n");
  2213. signal_socks_failure (s5r,
  2214. SOCKS5_STATUS_GENERAL_FAILURE);
  2215. return;
  2216. }
  2217. s5r->state = SOCKS5_DATA_TRANSFER;
  2218. signal_socks_success (s5r);
  2219. }
  2220. /**
  2221. * Remove the first @a len bytes from the beginning of the read buffer.
  2222. *
  2223. * @param s5r the handle clear the read buffer for
  2224. * @param len number of bytes in read buffer to advance
  2225. */
  2226. static void
  2227. clear_from_s5r_rbuf (struct Socks5Request *s5r,
  2228. size_t len)
  2229. {
  2230. GNUNET_assert (len <= s5r->rbuf_len);
  2231. memmove (s5r->rbuf,
  2232. &s5r->rbuf[len],
  2233. s5r->rbuf_len - len);
  2234. s5r->rbuf_len -= len;
  2235. }
  2236. /**
  2237. * Read data from incoming Socks5 connection
  2238. *
  2239. * @param cls the closure with the `struct Socks5Request`
  2240. * @param tc the scheduler context
  2241. */
  2242. static void
  2243. do_s5r_read (void *cls,
  2244. const struct GNUNET_SCHEDULER_TaskContext *tc)
  2245. {
  2246. struct Socks5Request *s5r = cls;
  2247. const struct Socks5ClientHelloMessage *c_hello;
  2248. struct Socks5ServerHelloMessage *s_hello;
  2249. const struct Socks5ClientRequestMessage *c_req;
  2250. ssize_t rlen;
  2251. size_t alen;
  2252. s5r->rtask = NULL;
  2253. if ( (NULL != tc->read_ready) &&
  2254. (GNUNET_NETWORK_fdset_isset (tc->read_ready, s5r->sock)) )
  2255. {
  2256. rlen = GNUNET_NETWORK_socket_recv (s5r->sock,
  2257. &s5r->rbuf[s5r->rbuf_len],
  2258. sizeof (s5r->rbuf) - s5r->rbuf_len);
  2259. if (rlen <= 0)
  2260. {
  2261. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2262. "socks5 client disconnected.\n");
  2263. cleanup_s5r (s5r);
  2264. return;
  2265. }
  2266. s5r->rbuf_len += rlen;
  2267. }
  2268. s5r->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
  2269. s5r->sock,
  2270. &do_s5r_read, s5r);
  2271. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2272. "Processing %u bytes of socks data in state %d\n",
  2273. s5r->rbuf_len,
  2274. s5r->state);
  2275. switch (s5r->state)
  2276. {
  2277. case SOCKS5_INIT:
  2278. c_hello = (const struct Socks5ClientHelloMessage*) &s5r->rbuf;
  2279. if ( (s5r->rbuf_len < sizeof (struct Socks5ClientHelloMessage)) ||
  2280. (s5r->rbuf_len < sizeof (struct Socks5ClientHelloMessage) + c_hello->num_auth_methods) )
  2281. return; /* need more data */
  2282. if (SOCKS_VERSION_5 != c_hello->version)
  2283. {
  2284. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  2285. _("Unsupported socks version %d\n"),
  2286. (int) c_hello->version);
  2287. cleanup_s5r (s5r);
  2288. return;
  2289. }
  2290. clear_from_s5r_rbuf (s5r,
  2291. sizeof (struct Socks5ClientHelloMessage) + c_hello->num_auth_methods);
  2292. GNUNET_assert (0 == s5r->wbuf_len);
  2293. s_hello = (struct Socks5ServerHelloMessage *) &s5r->wbuf;
  2294. s5r->wbuf_len = sizeof (struct Socks5ServerHelloMessage);
  2295. s_hello->version = SOCKS_VERSION_5;
  2296. s_hello->auth_method = SOCKS_AUTH_NONE;
  2297. GNUNET_assert (NULL == s5r->wtask);
  2298. s5r->wtask = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
  2299. s5r->sock,
  2300. &do_write, s5r);
  2301. s5r->state = SOCKS5_REQUEST;
  2302. return;
  2303. case SOCKS5_REQUEST:
  2304. c_req = (const struct Socks5ClientRequestMessage *) &s5r->rbuf;
  2305. if (s5r->rbuf_len < sizeof (struct Socks5ClientRequestMessage))
  2306. return;
  2307. switch (c_req->command)
  2308. {
  2309. case SOCKS5_CMD_TCP_STREAM:
  2310. /* handled below */
  2311. break;
  2312. default:
  2313. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  2314. _("Unsupported socks command %d\n"),
  2315. (int) c_req->command);
  2316. signal_socks_failure (s5r,
  2317. SOCKS5_STATUS_COMMAND_NOT_SUPPORTED);
  2318. return;
  2319. }
  2320. switch (c_req->addr_type)
  2321. {
  2322. case SOCKS5_AT_IPV4:
  2323. {
  2324. const struct in_addr *v4 = (const struct in_addr *) &c_req[1];
  2325. const uint16_t *port = (const uint16_t *) &v4[1];
  2326. struct sockaddr_in *in;
  2327. s5r->port = ntohs (*port);
  2328. if (HTTPS_PORT == s5r->port)
  2329. {
  2330. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  2331. _("SSL connection to plain IPv4 address requested\n"));
  2332. signal_socks_failure (s5r,
  2333. SOCKS5_STATUS_CONNECTION_NOT_ALLOWED_BY_RULE);
  2334. return;
  2335. }
  2336. alen = sizeof (struct in_addr);
  2337. if (s5r->rbuf_len < sizeof (struct Socks5ClientRequestMessage) +
  2338. alen + sizeof (uint16_t))
  2339. return; /* need more data */
  2340. in = (struct sockaddr_in *) &s5r->destination_address;
  2341. in->sin_family = AF_INET;
  2342. in->sin_addr = *v4;
  2343. in->sin_port = *port;
  2344. #if HAVE_SOCKADDR_IN_SIN_LEN
  2345. in->sin_len = sizeof (*in);
  2346. #endif
  2347. s5r->state = SOCKS5_DATA_TRANSFER;
  2348. }
  2349. break;
  2350. case SOCKS5_AT_IPV6:
  2351. {
  2352. const struct in6_addr *v6 = (const struct in6_addr *) &c_req[1];
  2353. const uint16_t *port = (const uint16_t *) &v6[1];
  2354. struct sockaddr_in6 *in;
  2355. s5r->port = ntohs (*port);
  2356. if (HTTPS_PORT == s5r->port)
  2357. {
  2358. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  2359. _("SSL connection to plain IPv4 address requested\n"));
  2360. signal_socks_failure (s5r,
  2361. SOCKS5_STATUS_CONNECTION_NOT_ALLOWED_BY_RULE);
  2362. return;
  2363. }
  2364. alen = sizeof (struct in6_addr);
  2365. if (s5r->rbuf_len < sizeof (struct Socks5ClientRequestMessage) +
  2366. alen + sizeof (uint16_t))
  2367. return; /* need more data */
  2368. in = (struct sockaddr_in6 *) &s5r->destination_address;
  2369. in->sin6_family = AF_INET6;
  2370. in->sin6_addr = *v6;
  2371. in->sin6_port = *port;
  2372. #if HAVE_SOCKADDR_IN_SIN_LEN
  2373. in->sin6_len = sizeof (*in);
  2374. #endif
  2375. s5r->state = SOCKS5_DATA_TRANSFER;
  2376. }
  2377. break;
  2378. case SOCKS5_AT_DOMAINNAME:
  2379. {
  2380. const uint8_t *dom_len;
  2381. const char *dom_name;
  2382. const uint16_t *port;
  2383. dom_len = (const uint8_t *) &c_req[1];
  2384. alen = *dom_len + 1;
  2385. if (s5r->rbuf_len < sizeof (struct Socks5ClientRequestMessage) +
  2386. alen + sizeof (uint16_t))
  2387. return; /* need more data */
  2388. dom_name = (const char *) &dom_len[1];
  2389. port = (const uint16_t*) &dom_name[*dom_len];
  2390. s5r->domain = GNUNET_strndup (dom_name, *dom_len);
  2391. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2392. "Requested connection is to %s:%d\n",
  2393. s5r->domain,
  2394. ntohs (*port));
  2395. s5r->state = SOCKS5_RESOLVING;
  2396. s5r->port = ntohs (*port);
  2397. s5r->gns_lookup = GNUNET_GNS_lookup (gns_handle,
  2398. s5r->domain,
  2399. &local_gns_zone,
  2400. GNUNET_DNSPARSER_TYPE_A,
  2401. GNUNET_NO /* only cached */,
  2402. (GNUNET_YES == do_shorten) ? &local_shorten_zone : NULL,
  2403. &handle_gns_result,
  2404. s5r);
  2405. break;
  2406. }
  2407. default:
  2408. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  2409. _("Unsupported socks address type %d\n"),
  2410. (int) c_req->addr_type);
  2411. signal_socks_failure (s5r,
  2412. SOCKS5_STATUS_ADDRESS_TYPE_NOT_SUPPORTED);
  2413. return;
  2414. }
  2415. clear_from_s5r_rbuf (s5r,
  2416. sizeof (struct Socks5ClientRequestMessage) +
  2417. alen + sizeof (uint16_t));
  2418. if (0 != s5r->rbuf_len)
  2419. {
  2420. /* read more bytes than healthy, why did the client send more!? */
  2421. GNUNET_break_op (0);
  2422. signal_socks_failure (s5r,
  2423. SOCKS5_STATUS_GENERAL_FAILURE);
  2424. return;
  2425. }
  2426. if (SOCKS5_DATA_TRANSFER == s5r->state)
  2427. {
  2428. /* if we are not waiting for GNS resolution, signal success */
  2429. signal_socks_success (s5r);
  2430. }
  2431. /* We are done reading right now */
  2432. GNUNET_SCHEDULER_cancel (s5r->rtask);
  2433. s5r->rtask = NULL;
  2434. return;
  2435. case SOCKS5_RESOLVING:
  2436. GNUNET_assert (0);
  2437. return;
  2438. case SOCKS5_DATA_TRANSFER:
  2439. GNUNET_assert (0);
  2440. return;
  2441. default:
  2442. GNUNET_assert (0);
  2443. return;
  2444. }
  2445. }
  2446. /**
  2447. * Accept new incoming connections
  2448. *
  2449. * @param cls the closure with the lsock4 or lsock6
  2450. * @param tc the scheduler context
  2451. */
  2452. static void
  2453. do_accept (void *cls,
  2454. const struct GNUNET_SCHEDULER_TaskContext *tc)
  2455. {
  2456. struct GNUNET_NETWORK_Handle *lsock = cls;
  2457. struct GNUNET_NETWORK_Handle *s;
  2458. struct Socks5Request *s5r;
  2459. if (lsock == lsock4)
  2460. ltask4 = NULL;
  2461. else
  2462. ltask6 = NULL;
  2463. if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
  2464. return;
  2465. if (lsock == lsock4)
  2466. ltask4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
  2467. lsock,
  2468. &do_accept, lsock);
  2469. else
  2470. ltask6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
  2471. lsock,
  2472. &do_accept, lsock);
  2473. s = GNUNET_NETWORK_socket_accept (lsock, NULL, NULL);
  2474. if (NULL == s)
  2475. {
  2476. GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "accept");
  2477. return;
  2478. }
  2479. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2480. "Got an inbound connection, waiting for data\n");
  2481. s5r = GNUNET_new (struct Socks5Request);
  2482. GNUNET_CONTAINER_DLL_insert (s5r_head,
  2483. s5r_tail,
  2484. s5r);
  2485. s5r->sock = s;
  2486. s5r->state = SOCKS5_INIT;
  2487. s5r->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
  2488. s5r->sock,
  2489. &do_s5r_read, s5r);
  2490. }
  2491. /* ******************* General / main code ********************* */
  2492. /**
  2493. * Task run on shutdown
  2494. *
  2495. * @param cls closure
  2496. * @param tc task context
  2497. */
  2498. static void
  2499. do_shutdown (void *cls,
  2500. const struct GNUNET_SCHEDULER_TaskContext *tc)
  2501. {
  2502. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  2503. "Shutting down...\n");
  2504. while (NULL != mhd_httpd_head)
  2505. kill_httpd (mhd_httpd_head);
  2506. while (NULL != s5r_head)
  2507. cleanup_s5r (s5r_head);
  2508. if (NULL != lsock4)
  2509. {
  2510. GNUNET_NETWORK_socket_close (lsock4);
  2511. lsock4 = NULL;
  2512. }
  2513. if (NULL != lsock6)
  2514. {
  2515. GNUNET_NETWORK_socket_close (lsock6);
  2516. lsock6 = NULL;
  2517. }
  2518. if (NULL != id_op)
  2519. {
  2520. GNUNET_IDENTITY_cancel (id_op);
  2521. id_op = NULL;
  2522. }
  2523. if (NULL != identity)
  2524. {
  2525. GNUNET_IDENTITY_disconnect (identity);
  2526. identity = NULL;
  2527. }
  2528. if (NULL != curl_multi)
  2529. {
  2530. curl_multi_cleanup (curl_multi);
  2531. curl_multi = NULL;
  2532. }
  2533. if (NULL != gns_handle)
  2534. {
  2535. GNUNET_GNS_disconnect (gns_handle);
  2536. gns_handle = NULL;
  2537. }
  2538. if (NULL != curl_download_task)
  2539. {
  2540. GNUNET_SCHEDULER_cancel (curl_download_task);
  2541. curl_download_task = NULL;
  2542. }
  2543. if (NULL != ltask4)
  2544. {
  2545. GNUNET_SCHEDULER_cancel (ltask4);
  2546. ltask4 = NULL;
  2547. }
  2548. if (NULL != ltask6)
  2549. {
  2550. GNUNET_SCHEDULER_cancel (ltask6);
  2551. ltask6 = NULL;
  2552. }
  2553. gnutls_x509_crt_deinit (proxy_ca.cert);
  2554. gnutls_x509_privkey_deinit (proxy_ca.key);
  2555. gnutls_global_deinit ();
  2556. }
  2557. /**
  2558. * Create an IPv4 listen socket bound to our port.
  2559. *
  2560. * @return NULL on error
  2561. */
  2562. static struct GNUNET_NETWORK_Handle *
  2563. bind_v4 ()
  2564. {
  2565. struct GNUNET_NETWORK_Handle *ls;
  2566. struct sockaddr_in sa4;
  2567. int eno;
  2568. memset (&sa4, 0, sizeof (sa4));
  2569. sa4.sin_family = AF_INET;
  2570. sa4.sin_port = htons (port);
  2571. #if HAVE_SOCKADDR_IN_SIN_LEN
  2572. sa4.sin_len = sizeof (sa4);
  2573. #endif
  2574. ls = GNUNET_NETWORK_socket_create (AF_INET,
  2575. SOCK_STREAM,
  2576. 0);
  2577. if (NULL == ls)
  2578. return NULL;
  2579. if (GNUNET_OK !=
  2580. GNUNET_NETWORK_socket_bind (ls, (const struct sockaddr *) &sa4,
  2581. sizeof (sa4)))
  2582. {
  2583. eno = errno;
  2584. GNUNET_NETWORK_socket_close (ls);
  2585. errno = eno;
  2586. return NULL;
  2587. }
  2588. return ls;
  2589. }
  2590. /**
  2591. * Create an IPv6 listen socket bound to our port.
  2592. *
  2593. * @return NULL on error
  2594. */
  2595. static struct GNUNET_NETWORK_Handle *
  2596. bind_v6 ()
  2597. {
  2598. struct GNUNET_NETWORK_Handle *ls;
  2599. struct sockaddr_in6 sa6;
  2600. int eno;
  2601. memset (&sa6, 0, sizeof (sa6));
  2602. sa6.sin6_family = AF_INET6;
  2603. sa6.sin6_port = htons (port);
  2604. #if HAVE_SOCKADDR_IN_SIN_LEN
  2605. sa6.sin6_len = sizeof (sa6);
  2606. #endif
  2607. ls = GNUNET_NETWORK_socket_create (AF_INET6,
  2608. SOCK_STREAM,
  2609. 0);
  2610. if (NULL == ls)
  2611. return NULL;
  2612. if (GNUNET_OK !=
  2613. GNUNET_NETWORK_socket_bind (ls, (const struct sockaddr *) &sa6,
  2614. sizeof (sa6)))
  2615. {
  2616. eno = errno;
  2617. GNUNET_NETWORK_socket_close (ls);
  2618. errno = eno;
  2619. return NULL;
  2620. }
  2621. return ls;
  2622. }
  2623. /**
  2624. * Continue initialization after we have our zone information.
  2625. */
  2626. static void
  2627. run_cont ()
  2628. {
  2629. struct MhdHttpList *hd;
  2630. /* Open listen socket for socks proxy */
  2631. lsock6 = bind_v6 ();
  2632. if (NULL == lsock6)
  2633. GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
  2634. else
  2635. {
  2636. if (GNUNET_OK != GNUNET_NETWORK_socket_listen (lsock6, 5))
  2637. {
  2638. GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen");
  2639. GNUNET_NETWORK_socket_close (lsock6);
  2640. lsock6 = NULL;
  2641. }
  2642. else
  2643. {
  2644. ltask6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
  2645. lsock6, &do_accept, lsock6);
  2646. }
  2647. }
  2648. lsock4 = bind_v4 ();
  2649. if (NULL == lsock4)
  2650. GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
  2651. else
  2652. {
  2653. if (GNUNET_OK != GNUNET_NETWORK_socket_listen (lsock4, 5))
  2654. {
  2655. GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen");
  2656. GNUNET_NETWORK_socket_close (lsock4);
  2657. lsock4 = NULL;
  2658. }
  2659. else
  2660. {
  2661. ltask4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
  2662. lsock4, &do_accept, lsock4);
  2663. }
  2664. }
  2665. if ( (NULL == lsock4) &&
  2666. (NULL == lsock6) )
  2667. {
  2668. GNUNET_SCHEDULER_shutdown ();
  2669. return;
  2670. }
  2671. if (0 != curl_global_init (CURL_GLOBAL_WIN32))
  2672. {
  2673. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  2674. "cURL global init failed!\n");
  2675. GNUNET_SCHEDULER_shutdown ();
  2676. return;
  2677. }
  2678. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2679. "Proxy listens on port %u\n",
  2680. port);
  2681. /* start MHD daemon for HTTP */
  2682. hd = GNUNET_new (struct MhdHttpList);
  2683. hd->daemon = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_NO_LISTEN_SOCKET,
  2684. 0,
  2685. NULL, NULL,
  2686. &create_response, hd,
  2687. MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16,
  2688. MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb, NULL,
  2689. MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback, NULL,
  2690. MHD_OPTION_END);
  2691. if (NULL == hd->daemon)
  2692. {
  2693. GNUNET_free (hd);
  2694. GNUNET_SCHEDULER_shutdown ();
  2695. return;
  2696. }
  2697. httpd = hd;
  2698. GNUNET_CONTAINER_DLL_insert (mhd_httpd_head, mhd_httpd_tail, hd);
  2699. }
  2700. /**
  2701. * Method called to inform about the egos of the shorten zone of this peer.
  2702. *
  2703. * When used with #GNUNET_IDENTITY_create or #GNUNET_IDENTITY_get,
  2704. * this function is only called ONCE, and 'NULL' being passed in
  2705. * @a ego does indicate an error (i.e. name is taken or no default
  2706. * value is known). If @a ego is non-NULL and if '*ctx'
  2707. * is set in those callbacks, the value WILL be passed to a subsequent
  2708. * call to the identity callback of #GNUNET_IDENTITY_connect (if
  2709. * that one was not NULL).
  2710. *
  2711. * @param cls closure, NULL
  2712. * @param ego ego handle
  2713. * @param ctx context for application to store data for this ego
  2714. * (during the lifetime of this process, initially NULL)
  2715. * @param name name assigned by the user for this ego,
  2716. * NULL if the user just deleted the ego and it
  2717. * must thus no longer be used
  2718. */
  2719. static void
  2720. identity_shorten_cb (void *cls,
  2721. struct GNUNET_IDENTITY_Ego *ego,
  2722. void **ctx,
  2723. const char *name)
  2724. {
  2725. id_op = NULL;
  2726. if (NULL == ego)
  2727. {
  2728. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  2729. _("No ego configured for `shorten-zone`\n"));
  2730. }
  2731. else
  2732. {
  2733. local_shorten_zone = *GNUNET_IDENTITY_ego_get_private_key (ego);
  2734. do_shorten = GNUNET_YES;
  2735. }
  2736. run_cont ();
  2737. }
  2738. /**
  2739. * Method called to inform about the egos of the master zone of this peer.
  2740. *
  2741. * When used with #GNUNET_IDENTITY_create or #GNUNET_IDENTITY_get,
  2742. * this function is only called ONCE, and 'NULL' being passed in
  2743. * @a ego does indicate an error (i.e. name is taken or no default
  2744. * value is known). If @a ego is non-NULL and if '*ctx'
  2745. * is set in those callbacks, the value WILL be passed to a subsequent
  2746. * call to the identity callback of #GNUNET_IDENTITY_connect (if
  2747. * that one was not NULL).
  2748. *
  2749. * @param cls closure, NULL
  2750. * @param ego ego handle
  2751. * @param ctx context for application to store data for this ego
  2752. * (during the lifetime of this process, initially NULL)
  2753. * @param name name assigned by the user for this ego,
  2754. * NULL if the user just deleted the ego and it
  2755. * must thus no longer be used
  2756. */
  2757. static void
  2758. identity_master_cb (void *cls,
  2759. struct GNUNET_IDENTITY_Ego *ego,
  2760. void **ctx,
  2761. const char *name)
  2762. {
  2763. id_op = NULL;
  2764. if (NULL == ego)
  2765. {
  2766. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  2767. _("No ego configured for `%s`\n"),
  2768. "gns-proxy");
  2769. GNUNET_SCHEDULER_shutdown ();
  2770. return;
  2771. }
  2772. GNUNET_IDENTITY_ego_get_public_key (ego,
  2773. &local_gns_zone);
  2774. id_op = GNUNET_IDENTITY_get (identity,
  2775. "gns-short",
  2776. &identity_shorten_cb,
  2777. NULL);
  2778. }
  2779. /**
  2780. * Main function that will be run
  2781. *
  2782. * @param cls closure
  2783. * @param args remaining command-line arguments
  2784. * @param cfgfile name of the configuration file used (for saving, can be NULL!)
  2785. * @param c configuration
  2786. */
  2787. static void
  2788. run (void *cls, char *const *args, const char *cfgfile,
  2789. const struct GNUNET_CONFIGURATION_Handle *c)
  2790. {
  2791. char* cafile_cfg = NULL;
  2792. char* cafile;
  2793. cfg = c;
  2794. if (NULL == (curl_multi = curl_multi_init ()))
  2795. {
  2796. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  2797. "Failed to create cURL multi handle!\n");
  2798. return;
  2799. }
  2800. cafile = cafile_opt;
  2801. if (NULL == cafile)
  2802. {
  2803. if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns-proxy",
  2804. "PROXY_CACERT",
  2805. &cafile_cfg))
  2806. {
  2807. GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
  2808. "gns-proxy",
  2809. "PROXY_CACERT");
  2810. return;
  2811. }
  2812. cafile = cafile_cfg;
  2813. }
  2814. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2815. "Using %s as CA\n", cafile);
  2816. gnutls_global_init ();
  2817. gnutls_x509_crt_init (&proxy_ca.cert);
  2818. gnutls_x509_privkey_init (&proxy_ca.key);
  2819. if ( (GNUNET_OK != load_cert_from_file (proxy_ca.cert, cafile)) ||
  2820. (GNUNET_OK != load_key_from_file (proxy_ca.key, cafile)) )
  2821. {
  2822. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  2823. _("Failed to load SSL/TLS key and certificate from `%s'\n"),
  2824. cafile);
  2825. gnutls_x509_crt_deinit (proxy_ca.cert);
  2826. gnutls_x509_privkey_deinit (proxy_ca.key);
  2827. gnutls_global_deinit ();
  2828. GNUNET_free_non_null (cafile_cfg);
  2829. return;
  2830. }
  2831. GNUNET_free_non_null (cafile_cfg);
  2832. if (NULL == (gns_handle = GNUNET_GNS_connect (cfg)))
  2833. {
  2834. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  2835. "Unable to connect to GNS!\n");
  2836. gnutls_x509_crt_deinit (proxy_ca.cert);
  2837. gnutls_x509_privkey_deinit (proxy_ca.key);
  2838. gnutls_global_deinit ();
  2839. return;
  2840. }
  2841. identity = GNUNET_IDENTITY_connect (cfg,
  2842. NULL, NULL);
  2843. id_op = GNUNET_IDENTITY_get (identity,
  2844. "gns-proxy",
  2845. &identity_master_cb,
  2846. NULL);
  2847. GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
  2848. &do_shutdown, NULL);
  2849. }
  2850. /**
  2851. * The main function for gnunet-gns-proxy.
  2852. *
  2853. * @param argc number of arguments from the command line
  2854. * @param argv command line arguments
  2855. * @return 0 ok, 1 on error
  2856. */
  2857. int
  2858. main (int argc, char *const *argv)
  2859. {
  2860. static const struct GNUNET_GETOPT_CommandLineOption options[] = {
  2861. {'p', "port", NULL,
  2862. gettext_noop ("listen on specified port (default: 7777)"), 1,
  2863. &GNUNET_GETOPT_set_ulong, &port},
  2864. {'a', "authority", NULL,
  2865. gettext_noop ("pem file to use as CA"), 1,
  2866. &GNUNET_GETOPT_set_string, &cafile_opt},
  2867. GNUNET_GETOPT_OPTION_END
  2868. };
  2869. static const char* page =
  2870. "<html><head><title>gnunet-gns-proxy</title>"
  2871. "</head><body>cURL fail</body></html>";
  2872. int ret;
  2873. if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
  2874. return 2;
  2875. GNUNET_log_setup ("gnunet-gns-proxy", "WARNING", NULL);
  2876. curl_failure_response = MHD_create_response_from_buffer (strlen (page),
  2877. (void*)page,
  2878. MHD_RESPMEM_PERSISTENT);
  2879. ret =
  2880. (GNUNET_OK ==
  2881. GNUNET_PROGRAM_run (argc, argv, "gnunet-gns-proxy",
  2882. _("GNUnet GNS proxy"),
  2883. options,
  2884. &run, NULL)) ? 0 : 1;
  2885. MHD_destroy_response (curl_failure_response);
  2886. GNUNET_free_non_null ((char *) argv);
  2887. GNUNET_CRYPTO_ecdsa_key_clear (&local_shorten_zone);
  2888. return ret;
  2889. }
  2890. /* end of gnunet-gns-proxy.c */