├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── ipt2socks.service ├── libev ├── config.h ├── ev.c ├── ev.h ├── ev_epoll.c ├── ev_vars.h └── ev_wrap.h └── src ├── ipt2socks.c ├── logutils.h ├── lrucache.c ├── lrucache.h ├── netutils.c ├── netutils.h ├── protocol.c ├── protocol.h └── uthash.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.gch 3 | a.out 4 | ipt2socks 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU AFFERO GENERAL PUBLIC LICENSE 2 | Version 3, 19 November 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU Affero General Public License is a free, copyleft license for 11 | software and other kinds of works, specifically designed to ensure 12 | cooperation with the community in the case of network server software. 13 | 14 | The licenses for most software and other practical works are designed 15 | to take away your freedom to share and change the works. By contrast, 16 | our General Public Licenses are intended to guarantee your freedom to 17 | share and change all versions of a program--to make sure it remains free 18 | software for all its users. 19 | 20 | When we speak of free software, we are referring to freedom, not 21 | price. Our General Public Licenses are designed to make sure that you 22 | have the freedom to distribute copies of free software (and charge for 23 | them if you wish), that you receive source code or can get it if you 24 | want it, that you can change the software or use pieces of it in new 25 | free programs, and that you know you can do these things. 26 | 27 | Developers that use our General Public Licenses protect your rights 28 | with two steps: (1) assert copyright on the software, and (2) offer 29 | you this License which gives you legal permission to copy, distribute 30 | and/or modify the software. 31 | 32 | A secondary benefit of defending all users' freedom is that 33 | improvements made in alternate versions of the program, if they 34 | receive widespread use, become available for other developers to 35 | incorporate. Many developers of free software are heartened and 36 | encouraged by the resulting cooperation. However, in the case of 37 | software used on network servers, this result may fail to come about. 38 | The GNU General Public License permits making a modified version and 39 | letting the public access it on a server without ever releasing its 40 | source code to the public. 41 | 42 | The GNU Affero General Public License is designed specifically to 43 | ensure that, in such cases, the modified source code becomes available 44 | to the community. It requires the operator of a network server to 45 | provide the source code of the modified version running there to the 46 | users of that server. Therefore, public use of a modified version, on 47 | a publicly accessible server, gives the public access to the source 48 | code of the modified version. 49 | 50 | An older license, called the Affero General Public License and 51 | published by Affero, was designed to accomplish similar goals. This is 52 | a different license, not a version of the Affero GPL, but Affero has 53 | released a new version of the Affero GPL which permits relicensing under 54 | this license. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | TERMS AND CONDITIONS 60 | 61 | 0. Definitions. 62 | 63 | "This License" refers to version 3 of the GNU Affero General Public License. 64 | 65 | "Copyright" also means copyright-like laws that apply to other kinds of 66 | works, such as semiconductor masks. 67 | 68 | "The Program" refers to any copyrightable work licensed under this 69 | License. Each licensee is addressed as "you". "Licensees" and 70 | "recipients" may be individuals or organizations. 71 | 72 | To "modify" a work means to copy from or adapt all or part of the work 73 | in a fashion requiring copyright permission, other than the making of an 74 | exact copy. The resulting work is called a "modified version" of the 75 | earlier work or a work "based on" the earlier work. 76 | 77 | A "covered work" means either the unmodified Program or a work based 78 | on the Program. 79 | 80 | To "propagate" a work means to do anything with it that, without 81 | permission, would make you directly or secondarily liable for 82 | infringement under applicable copyright law, except executing it on a 83 | computer or modifying a private copy. Propagation includes copying, 84 | distribution (with or without modification), making available to the 85 | public, and in some countries other activities as well. 86 | 87 | To "convey" a work means any kind of propagation that enables other 88 | parties to make or receive copies. Mere interaction with a user through 89 | a computer network, with no transfer of a copy, is not conveying. 90 | 91 | An interactive user interface displays "Appropriate Legal Notices" 92 | to the extent that it includes a convenient and prominently visible 93 | feature that (1) displays an appropriate copyright notice, and (2) 94 | tells the user that there is no warranty for the work (except to the 95 | extent that warranties are provided), that licensees may convey the 96 | work under this License, and how to view a copy of this License. If 97 | the interface presents a list of user commands or options, such as a 98 | menu, a prominent item in the list meets this criterion. 99 | 100 | 1. Source Code. 101 | 102 | The "source code" for a work means the preferred form of the work 103 | for making modifications to it. "Object code" means any non-source 104 | form of a work. 105 | 106 | A "Standard Interface" means an interface that either is an official 107 | standard defined by a recognized standards body, or, in the case of 108 | interfaces specified for a particular programming language, one that 109 | is widely used among developers working in that language. 110 | 111 | The "System Libraries" of an executable work include anything, other 112 | than the work as a whole, that (a) is included in the normal form of 113 | packaging a Major Component, but which is not part of that Major 114 | Component, and (b) serves only to enable use of the work with that 115 | Major Component, or to implement a Standard Interface for which an 116 | implementation is available to the public in source code form. A 117 | "Major Component", in this context, means a major essential component 118 | (kernel, window system, and so on) of the specific operating system 119 | (if any) on which the executable work runs, or a compiler used to 120 | produce the work, or an object code interpreter used to run it. 121 | 122 | The "Corresponding Source" for a work in object code form means all 123 | the source code needed to generate, install, and (for an executable 124 | work) run the object code and to modify the work, including scripts to 125 | control those activities. However, it does not include the work's 126 | System Libraries, or general-purpose tools or generally available free 127 | programs which are used unmodified in performing those activities but 128 | which are not part of the work. For example, Corresponding Source 129 | includes interface definition files associated with source files for 130 | the work, and the source code for shared libraries and dynamically 131 | linked subprograms that the work is specifically designed to require, 132 | such as by intimate data communication or control flow between those 133 | subprograms and other parts of the work. 134 | 135 | The Corresponding Source need not include anything that users 136 | can regenerate automatically from other parts of the Corresponding 137 | Source. 138 | 139 | The Corresponding Source for a work in source code form is that 140 | same work. 141 | 142 | 2. Basic Permissions. 143 | 144 | All rights granted under this License are granted for the term of 145 | copyright on the Program, and are irrevocable provided the stated 146 | conditions are met. This License explicitly affirms your unlimited 147 | permission to run the unmodified Program. The output from running a 148 | covered work is covered by this License only if the output, given its 149 | content, constitutes a covered work. This License acknowledges your 150 | rights of fair use or other equivalent, as provided by copyright law. 151 | 152 | You may make, run and propagate covered works that you do not 153 | convey, without conditions so long as your license otherwise remains 154 | in force. You may convey covered works to others for the sole purpose 155 | of having them make modifications exclusively for you, or provide you 156 | with facilities for running those works, provided that you comply with 157 | the terms of this License in conveying all material for which you do 158 | not control copyright. Those thus making or running the covered works 159 | for you must do so exclusively on your behalf, under your direction 160 | and control, on terms that prohibit them from making any copies of 161 | your copyrighted material outside their relationship with you. 162 | 163 | Conveying under any other circumstances is permitted solely under 164 | the conditions stated below. Sublicensing is not allowed; section 10 165 | makes it unnecessary. 166 | 167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 168 | 169 | No covered work shall be deemed part of an effective technological 170 | measure under any applicable law fulfilling obligations under article 171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 172 | similar laws prohibiting or restricting circumvention of such 173 | measures. 174 | 175 | When you convey a covered work, you waive any legal power to forbid 176 | circumvention of technological measures to the extent such circumvention 177 | is effected by exercising rights under this License with respect to 178 | the covered work, and you disclaim any intention to limit operation or 179 | modification of the work as a means of enforcing, against the work's 180 | users, your or third parties' legal rights to forbid circumvention of 181 | technological measures. 182 | 183 | 4. Conveying Verbatim Copies. 184 | 185 | You may convey verbatim copies of the Program's source code as you 186 | receive it, in any medium, provided that you conspicuously and 187 | appropriately publish on each copy an appropriate copyright notice; 188 | keep intact all notices stating that this License and any 189 | non-permissive terms added in accord with section 7 apply to the code; 190 | keep intact all notices of the absence of any warranty; and give all 191 | recipients a copy of this License along with the Program. 192 | 193 | You may charge any price or no price for each copy that you convey, 194 | and you may offer support or warranty protection for a fee. 195 | 196 | 5. Conveying Modified Source Versions. 197 | 198 | You may convey a work based on the Program, or the modifications to 199 | produce it from the Program, in the form of source code under the 200 | terms of section 4, provided that you also meet all of these conditions: 201 | 202 | a) The work must carry prominent notices stating that you modified 203 | it, and giving a relevant date. 204 | 205 | b) The work must carry prominent notices stating that it is 206 | released under this License and any conditions added under section 207 | 7. This requirement modifies the requirement in section 4 to 208 | "keep intact all notices". 209 | 210 | c) You must license the entire work, as a whole, under this 211 | License to anyone who comes into possession of a copy. This 212 | License will therefore apply, along with any applicable section 7 213 | additional terms, to the whole of the work, and all its parts, 214 | regardless of how they are packaged. This License gives no 215 | permission to license the work in any other way, but it does not 216 | invalidate such permission if you have separately received it. 217 | 218 | d) If the work has interactive user interfaces, each must display 219 | Appropriate Legal Notices; however, if the Program has interactive 220 | interfaces that do not display Appropriate Legal Notices, your 221 | work need not make them do so. 222 | 223 | A compilation of a covered work with other separate and independent 224 | works, which are not by their nature extensions of the covered work, 225 | and which are not combined with it such as to form a larger program, 226 | in or on a volume of a storage or distribution medium, is called an 227 | "aggregate" if the compilation and its resulting copyright are not 228 | used to limit the access or legal rights of the compilation's users 229 | beyond what the individual works permit. Inclusion of a covered work 230 | in an aggregate does not cause this License to apply to the other 231 | parts of the aggregate. 232 | 233 | 6. Conveying Non-Source Forms. 234 | 235 | You may convey a covered work in object code form under the terms 236 | of sections 4 and 5, provided that you also convey the 237 | machine-readable Corresponding Source under the terms of this License, 238 | in one of these ways: 239 | 240 | a) Convey the object code in, or embodied in, a physical product 241 | (including a physical distribution medium), accompanied by the 242 | Corresponding Source fixed on a durable physical medium 243 | customarily used for software interchange. 244 | 245 | b) Convey the object code in, or embodied in, a physical product 246 | (including a physical distribution medium), accompanied by a 247 | written offer, valid for at least three years and valid for as 248 | long as you offer spare parts or customer support for that product 249 | model, to give anyone who possesses the object code either (1) a 250 | copy of the Corresponding Source for all the software in the 251 | product that is covered by this License, on a durable physical 252 | medium customarily used for software interchange, for a price no 253 | more than your reasonable cost of physically performing this 254 | conveying of source, or (2) access to copy the 255 | Corresponding Source from a network server at no charge. 256 | 257 | c) Convey individual copies of the object code with a copy of the 258 | written offer to provide the Corresponding Source. This 259 | alternative is allowed only occasionally and noncommercially, and 260 | only if you received the object code with such an offer, in accord 261 | with subsection 6b. 262 | 263 | d) Convey the object code by offering access from a designated 264 | place (gratis or for a charge), and offer equivalent access to the 265 | Corresponding Source in the same way through the same place at no 266 | further charge. You need not require recipients to copy the 267 | Corresponding Source along with the object code. If the place to 268 | copy the object code is a network server, the Corresponding Source 269 | may be on a different server (operated by you or a third party) 270 | that supports equivalent copying facilities, provided you maintain 271 | clear directions next to the object code saying where to find the 272 | Corresponding Source. Regardless of what server hosts the 273 | Corresponding Source, you remain obligated to ensure that it is 274 | available for as long as needed to satisfy these requirements. 275 | 276 | e) Convey the object code using peer-to-peer transmission, provided 277 | you inform other peers where the object code and Corresponding 278 | Source of the work are being offered to the general public at no 279 | charge under subsection 6d. 280 | 281 | A separable portion of the object code, whose source code is excluded 282 | from the Corresponding Source as a System Library, need not be 283 | included in conveying the object code work. 284 | 285 | A "User Product" is either (1) a "consumer product", which means any 286 | tangible personal property which is normally used for personal, family, 287 | or household purposes, or (2) anything designed or sold for incorporation 288 | into a dwelling. In determining whether a product is a consumer product, 289 | doubtful cases shall be resolved in favor of coverage. For a particular 290 | product received by a particular user, "normally used" refers to a 291 | typical or common use of that class of product, regardless of the status 292 | of the particular user or of the way in which the particular user 293 | actually uses, or expects or is expected to use, the product. A product 294 | is a consumer product regardless of whether the product has substantial 295 | commercial, industrial or non-consumer uses, unless such uses represent 296 | the only significant mode of use of the product. 297 | 298 | "Installation Information" for a User Product means any methods, 299 | procedures, authorization keys, or other information required to install 300 | and execute modified versions of a covered work in that User Product from 301 | a modified version of its Corresponding Source. The information must 302 | suffice to ensure that the continued functioning of the modified object 303 | code is in no case prevented or interfered with solely because 304 | modification has been made. 305 | 306 | If you convey an object code work under this section in, or with, or 307 | specifically for use in, a User Product, and the conveying occurs as 308 | part of a transaction in which the right of possession and use of the 309 | User Product is transferred to the recipient in perpetuity or for a 310 | fixed term (regardless of how the transaction is characterized), the 311 | Corresponding Source conveyed under this section must be accompanied 312 | by the Installation Information. But this requirement does not apply 313 | if neither you nor any third party retains the ability to install 314 | modified object code on the User Product (for example, the work has 315 | been installed in ROM). 316 | 317 | The requirement to provide Installation Information does not include a 318 | requirement to continue to provide support service, warranty, or updates 319 | for a work that has been modified or installed by the recipient, or for 320 | the User Product in which it has been modified or installed. Access to a 321 | network may be denied when the modification itself materially and 322 | adversely affects the operation of the network or violates the rules and 323 | protocols for communication across the network. 324 | 325 | Corresponding Source conveyed, and Installation Information provided, 326 | in accord with this section must be in a format that is publicly 327 | documented (and with an implementation available to the public in 328 | source code form), and must require no special password or key for 329 | unpacking, reading or copying. 330 | 331 | 7. Additional Terms. 332 | 333 | "Additional permissions" are terms that supplement the terms of this 334 | License by making exceptions from one or more of its conditions. 335 | Additional permissions that are applicable to the entire Program shall 336 | be treated as though they were included in this License, to the extent 337 | that they are valid under applicable law. If additional permissions 338 | apply only to part of the Program, that part may be used separately 339 | under those permissions, but the entire Program remains governed by 340 | this License without regard to the additional permissions. 341 | 342 | When you convey a copy of a covered work, you may at your option 343 | remove any additional permissions from that copy, or from any part of 344 | it. (Additional permissions may be written to require their own 345 | removal in certain cases when you modify the work.) You may place 346 | additional permissions on material, added by you to a covered work, 347 | for which you have or can give appropriate copyright permission. 348 | 349 | Notwithstanding any other provision of this License, for material you 350 | add to a covered work, you may (if authorized by the copyright holders of 351 | that material) supplement the terms of this License with terms: 352 | 353 | a) Disclaiming warranty or limiting liability differently from the 354 | terms of sections 15 and 16 of this License; or 355 | 356 | b) Requiring preservation of specified reasonable legal notices or 357 | author attributions in that material or in the Appropriate Legal 358 | Notices displayed by works containing it; or 359 | 360 | c) Prohibiting misrepresentation of the origin of that material, or 361 | requiring that modified versions of such material be marked in 362 | reasonable ways as different from the original version; or 363 | 364 | d) Limiting the use for publicity purposes of names of licensors or 365 | authors of the material; or 366 | 367 | e) Declining to grant rights under trademark law for use of some 368 | trade names, trademarks, or service marks; or 369 | 370 | f) Requiring indemnification of licensors and authors of that 371 | material by anyone who conveys the material (or modified versions of 372 | it) with contractual assumptions of liability to the recipient, for 373 | any liability that these contractual assumptions directly impose on 374 | those licensors and authors. 375 | 376 | All other non-permissive additional terms are considered "further 377 | restrictions" within the meaning of section 10. If the Program as you 378 | received it, or any part of it, contains a notice stating that it is 379 | governed by this License along with a term that is a further 380 | restriction, you may remove that term. If a license document contains 381 | a further restriction but permits relicensing or conveying under this 382 | License, you may add to a covered work material governed by the terms 383 | of that license document, provided that the further restriction does 384 | not survive such relicensing or conveying. 385 | 386 | If you add terms to a covered work in accord with this section, you 387 | must place, in the relevant source files, a statement of the 388 | additional terms that apply to those files, or a notice indicating 389 | where to find the applicable terms. 390 | 391 | Additional terms, permissive or non-permissive, may be stated in the 392 | form of a separately written license, or stated as exceptions; 393 | the above requirements apply either way. 394 | 395 | 8. Termination. 396 | 397 | You may not propagate or modify a covered work except as expressly 398 | provided under this License. Any attempt otherwise to propagate or 399 | modify it is void, and will automatically terminate your rights under 400 | this License (including any patent licenses granted under the third 401 | paragraph of section 11). 402 | 403 | However, if you cease all violation of this License, then your 404 | license from a particular copyright holder is reinstated (a) 405 | provisionally, unless and until the copyright holder explicitly and 406 | finally terminates your license, and (b) permanently, if the copyright 407 | holder fails to notify you of the violation by some reasonable means 408 | prior to 60 days after the cessation. 409 | 410 | Moreover, your license from a particular copyright holder is 411 | reinstated permanently if the copyright holder notifies you of the 412 | violation by some reasonable means, this is the first time you have 413 | received notice of violation of this License (for any work) from that 414 | copyright holder, and you cure the violation prior to 30 days after 415 | your receipt of the notice. 416 | 417 | Termination of your rights under this section does not terminate the 418 | licenses of parties who have received copies or rights from you under 419 | this License. If your rights have been terminated and not permanently 420 | reinstated, you do not qualify to receive new licenses for the same 421 | material under section 10. 422 | 423 | 9. Acceptance Not Required for Having Copies. 424 | 425 | You are not required to accept this License in order to receive or 426 | run a copy of the Program. Ancillary propagation of a covered work 427 | occurring solely as a consequence of using peer-to-peer transmission 428 | to receive a copy likewise does not require acceptance. However, 429 | nothing other than this License grants you permission to propagate or 430 | modify any covered work. These actions infringe copyright if you do 431 | not accept this License. Therefore, by modifying or propagating a 432 | covered work, you indicate your acceptance of this License to do so. 433 | 434 | 10. Automatic Licensing of Downstream Recipients. 435 | 436 | Each time you convey a covered work, the recipient automatically 437 | receives a license from the original licensors, to run, modify and 438 | propagate that work, subject to this License. You are not responsible 439 | for enforcing compliance by third parties with this License. 440 | 441 | An "entity transaction" is a transaction transferring control of an 442 | organization, or substantially all assets of one, or subdividing an 443 | organization, or merging organizations. If propagation of a covered 444 | work results from an entity transaction, each party to that 445 | transaction who receives a copy of the work also receives whatever 446 | licenses to the work the party's predecessor in interest had or could 447 | give under the previous paragraph, plus a right to possession of the 448 | Corresponding Source of the work from the predecessor in interest, if 449 | the predecessor has it or can get it with reasonable efforts. 450 | 451 | You may not impose any further restrictions on the exercise of the 452 | rights granted or affirmed under this License. For example, you may 453 | not impose a license fee, royalty, or other charge for exercise of 454 | rights granted under this License, and you may not initiate litigation 455 | (including a cross-claim or counterclaim in a lawsuit) alleging that 456 | any patent claim is infringed by making, using, selling, offering for 457 | sale, or importing the Program or any portion of it. 458 | 459 | 11. Patents. 460 | 461 | A "contributor" is a copyright holder who authorizes use under this 462 | License of the Program or a work on which the Program is based. The 463 | work thus licensed is called the contributor's "contributor version". 464 | 465 | A contributor's "essential patent claims" are all patent claims 466 | owned or controlled by the contributor, whether already acquired or 467 | hereafter acquired, that would be infringed by some manner, permitted 468 | by this License, of making, using, or selling its contributor version, 469 | but do not include claims that would be infringed only as a 470 | consequence of further modification of the contributor version. For 471 | purposes of this definition, "control" includes the right to grant 472 | patent sublicenses in a manner consistent with the requirements of 473 | this License. 474 | 475 | Each contributor grants you a non-exclusive, worldwide, royalty-free 476 | patent license under the contributor's essential patent claims, to 477 | make, use, sell, offer for sale, import and otherwise run, modify and 478 | propagate the contents of its contributor version. 479 | 480 | In the following three paragraphs, a "patent license" is any express 481 | agreement or commitment, however denominated, not to enforce a patent 482 | (such as an express permission to practice a patent or covenant not to 483 | sue for patent infringement). To "grant" such a patent license to a 484 | party means to make such an agreement or commitment not to enforce a 485 | patent against the party. 486 | 487 | If you convey a covered work, knowingly relying on a patent license, 488 | and the Corresponding Source of the work is not available for anyone 489 | to copy, free of charge and under the terms of this License, through a 490 | publicly available network server or other readily accessible means, 491 | then you must either (1) cause the Corresponding Source to be so 492 | available, or (2) arrange to deprive yourself of the benefit of the 493 | patent license for this particular work, or (3) arrange, in a manner 494 | consistent with the requirements of this License, to extend the patent 495 | license to downstream recipients. "Knowingly relying" means you have 496 | actual knowledge that, but for the patent license, your conveying the 497 | covered work in a country, or your recipient's use of the covered work 498 | in a country, would infringe one or more identifiable patents in that 499 | country that you have reason to believe are valid. 500 | 501 | If, pursuant to or in connection with a single transaction or 502 | arrangement, you convey, or propagate by procuring conveyance of, a 503 | covered work, and grant a patent license to some of the parties 504 | receiving the covered work authorizing them to use, propagate, modify 505 | or convey a specific copy of the covered work, then the patent license 506 | you grant is automatically extended to all recipients of the covered 507 | work and works based on it. 508 | 509 | A patent license is "discriminatory" if it does not include within 510 | the scope of its coverage, prohibits the exercise of, or is 511 | conditioned on the non-exercise of one or more of the rights that are 512 | specifically granted under this License. You may not convey a covered 513 | work if you are a party to an arrangement with a third party that is 514 | in the business of distributing software, under which you make payment 515 | to the third party based on the extent of your activity of conveying 516 | the work, and under which the third party grants, to any of the 517 | parties who would receive the covered work from you, a discriminatory 518 | patent license (a) in connection with copies of the covered work 519 | conveyed by you (or copies made from those copies), or (b) primarily 520 | for and in connection with specific products or compilations that 521 | contain the covered work, unless you entered into that arrangement, 522 | or that patent license was granted, prior to 28 March 2007. 523 | 524 | Nothing in this License shall be construed as excluding or limiting 525 | any implied license or other defenses to infringement that may 526 | otherwise be available to you under applicable patent law. 527 | 528 | 12. No Surrender of Others' Freedom. 529 | 530 | If conditions are imposed on you (whether by court order, agreement or 531 | otherwise) that contradict the conditions of this License, they do not 532 | excuse you from the conditions of this License. If you cannot convey a 533 | covered work so as to satisfy simultaneously your obligations under this 534 | License and any other pertinent obligations, then as a consequence you may 535 | not convey it at all. For example, if you agree to terms that obligate you 536 | to collect a royalty for further conveying from those to whom you convey 537 | the Program, the only way you could satisfy both those terms and this 538 | License would be to refrain entirely from conveying the Program. 539 | 540 | 13. Remote Network Interaction; Use with the GNU General Public License. 541 | 542 | Notwithstanding any other provision of this License, if you modify the 543 | Program, your modified version must prominently offer all users 544 | interacting with it remotely through a computer network (if your version 545 | supports such interaction) an opportunity to receive the Corresponding 546 | Source of your version by providing access to the Corresponding Source 547 | from a network server at no charge, through some standard or customary 548 | means of facilitating copying of software. This Corresponding Source 549 | shall include the Corresponding Source for any work covered by version 3 550 | of the GNU General Public License that is incorporated pursuant to the 551 | following paragraph. 552 | 553 | Notwithstanding any other provision of this License, you have 554 | permission to link or combine any covered work with a work licensed 555 | under version 3 of the GNU General Public License into a single 556 | combined work, and to convey the resulting work. The terms of this 557 | License will continue to apply to the part which is the covered work, 558 | but the work with which it is combined will remain governed by version 559 | 3 of the GNU General Public License. 560 | 561 | 14. Revised Versions of this License. 562 | 563 | The Free Software Foundation may publish revised and/or new versions of 564 | the GNU Affero General Public License from time to time. Such new versions 565 | will be similar in spirit to the present version, but may differ in detail to 566 | address new problems or concerns. 567 | 568 | Each version is given a distinguishing version number. If the 569 | Program specifies that a certain numbered version of the GNU Affero General 570 | Public License "or any later version" applies to it, you have the 571 | option of following the terms and conditions either of that numbered 572 | version or of any later version published by the Free Software 573 | Foundation. If the Program does not specify a version number of the 574 | GNU Affero General Public License, you may choose any version ever published 575 | by the Free Software Foundation. 576 | 577 | If the Program specifies that a proxy can decide which future 578 | versions of the GNU Affero General Public License can be used, that proxy's 579 | public statement of acceptance of a version permanently authorizes you 580 | to choose that version for the Program. 581 | 582 | Later license versions may give you additional or different 583 | permissions. However, no additional obligations are imposed on any 584 | author or copyright holder as a result of your choosing to follow a 585 | later version. 586 | 587 | 15. Disclaimer of Warranty. 588 | 589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 597 | 598 | 16. Limitation of Liability. 599 | 600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 608 | SUCH DAMAGES. 609 | 610 | 17. Interpretation of Sections 15 and 16. 611 | 612 | If the disclaimer of warranty and limitation of liability provided 613 | above cannot be given local legal effect according to their terms, 614 | reviewing courts shall apply local law that most closely approximates 615 | an absolute waiver of all civil liability in connection with the 616 | Program, unless a warranty or assumption of liability accompanies a 617 | copy of the Program in return for a fee. 618 | 619 | END OF TERMS AND CONDITIONS 620 | 621 | How to Apply These Terms to Your New Programs 622 | 623 | If you develop a new program, and you want it to be of the greatest 624 | possible use to the public, the best way to achieve this is to make it 625 | free software which everyone can redistribute and change under these terms. 626 | 627 | To do so, attach the following notices to the program. It is safest 628 | to attach them to the start of each source file to most effectively 629 | state the exclusion of warranty; and each file should have at least 630 | the "copyright" line and a pointer to where the full notice is found. 631 | 632 | 633 | Copyright (C) 634 | 635 | This program is free software: you can redistribute it and/or modify 636 | it under the terms of the GNU Affero General Public License as published 637 | by the Free Software Foundation, either version 3 of the License, or 638 | (at your option) any later version. 639 | 640 | This program is distributed in the hope that it will be useful, 641 | but WITHOUT ANY WARRANTY; without even the implied warranty of 642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 643 | GNU Affero General Public License for more details. 644 | 645 | You should have received a copy of the GNU Affero General Public License 646 | along with this program. If not, see . 647 | 648 | Also add information on how to contact you by electronic and paper mail. 649 | 650 | If your software can interact with users remotely through a computer 651 | network, you should also make sure that it provides a way for users to 652 | get its source. For example, if your program is a web application, its 653 | interface could display a "Source" link that leads users to an archive 654 | of the code. There are many ways you could offer source, and different 655 | solutions will be better for different programs; see section 13 for the 656 | specific requirements. 657 | 658 | You should also get your employer (if you work as a programmer) or school, 659 | if any, to sign a "copyright disclaimer" for the program, if necessary. 660 | For more information on this, and how to apply and follow the GNU AGPL, see 661 | . 662 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -std=c99 -Wall -Wextra -Wvla -pthread -O3 -flto -fno-strict-aliasing -ffunction-sections -fdata-sections -DNDEBUG 3 | LDFLAGS = -pthread -O3 -flto -fno-strict-aliasing -Wl,--gc-sections -s 4 | LIBS = -lm 5 | SRCS = src/ipt2socks.c src/lrucache.c src/netutils.c src/protocol.c libev/ev.c 6 | OBJS = $(SRCS:.c=.o) 7 | MAIN = ipt2socks 8 | DESTDIR = /usr/local/bin 9 | 10 | .PHONY: all install clean 11 | 12 | all: $(MAIN) 13 | 14 | install: $(MAIN) 15 | mkdir -p $(DESTDIR) 16 | install -m 0755 $(MAIN) $(DESTDIR) 17 | 18 | clean: 19 | $(RM) $(MAIN) src/*.o libev/*.o 20 | 21 | $(MAIN): $(OBJS) 22 | $(CC) $(LDFLAGS) -o $(MAIN) $(OBJS) $(LIBS) 23 | 24 | .c.o: 25 | $(CC) $(CFLAGS) -c $< -o $@ 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ipt2socks(libev) 2 | 3 | 类似 [redsocks](https://github.com/darkk/redsocks)、[redsocks2](https://github.com/semigodking/redsocks) 的实用工具,将 iptables/nftables (REDIRECT/TPROXY) 传入的流量转为 socks5(tcp/udp) 流量,除此之外不提供任何不必要的功能。 4 | 5 | 用例 1:配合透明代理使用(如 [ss-tproxy](https://github.com/zfl9/ss-tproxy)),为那些只支持 socks5 传入协议的“代理进程”提供 **iptables/nftables 透明代理** 传入协议的支持,比如 ss/ssr 的 ss-local/ssr-local、v2ray 的 socks5 传入协议、trojan 的 socks5 客户端等等。 6 | 7 | 用例 2:将透明代理主机上的“代理进程”分离出来,因为“代理”通常涉及加解密等耗性能的操作,如果透明代理主机性能比较弱,最好将“代理进程”放到另外一个性能更强的局域网主机去运行(提供 socks5 传入),然后在透明代理主机上运行 ipt2socks 来对接这个“代理”。ipt2socks 在设计和编码上特意考虑了性能,尽可能实现零拷贝,降低开销。 8 | 9 | ## 简要说明 10 | 11 | - 使用 splice() 系统调用,理想情况下可实现零拷贝。 12 | - IPv4 和 IPv6 双栈支持,支持 **纯 TPROXY** 透明代理模式。 13 | - TCP 透明代理提供 REDIRECT、TPROXY 两种方式,UDP 透明代理为 TPROXY 方式。 14 | - UDP 透明代理支持 Full Cone NAT,前提是后端的 socks5 服务器支持 Full Cone NAT。 15 | - 多线程 + SO_REUSEPORT 端口重用,每个线程运行各自独立的事件循环,性能提升显著。 16 | 17 | ## 如何编译 18 | 19 | > 为了方便使用,[releases](https://github.com/zfl9/ipt2socks/releases) 页面发布了 linux 下常见架构的 musl 静态链接二进制。 20 | 21 | ```bash 22 | git clone https://github.com/zfl9/ipt2socks 23 | cd ipt2socks 24 | make && sudo make install 25 | ``` 26 | 27 | ipt2socks 默认安装到 `/usr/local/bin/ipt2socks`,可安装到其它目录,如 `make install DESTDIR=/opt/local/bin`。 28 | 29 | 交叉编译时只需指定 CC 变量,如 `make CC=aarch64-linux-gnu-gcc`(若报错或异常,请执行 `make clean`,再试)。 30 | 31 | ## 如何运行 32 | 33 | ```bash 34 | # -s 指定 socks5 服务器 ip 35 | # -p 指定 socks5 服务器端口 36 | ipt2socks -s 127.0.0.1 -p 1080 37 | 38 | # 如果想后台运行,可以这样启动: 39 | (ipt2socks -s 127.0.0.1 -p 1080 >/var/log/ipt2socks.log &) 40 | ``` 41 | 42 | ipt2socks 启动后,配置相应 iptables/nftables 规则即可,关于 iptables 规则,可以看看: 43 | 44 | - https://github.com/zfl9/ss-tproxy 45 | - https://gist.github.com/zfl9/d52482118f38ce2c16195583dffc44d2 46 | 47 | ## 全部参数 48 | 49 | ```bash 50 | $ ipt2socks --help 51 | usage: ipt2socks . the existing options are as follows: 52 | -s, --server-addr socks5 server ip, default: 127.0.0.1 53 | -p, --server-port socks5 server port, default: 1080 54 | -a, --auth-username username for socks5 authentication 55 | -k, --auth-password password for socks5 authentication 56 | -b, --listen-addr4 listen ipv4 address, default: 127.0.0.1 57 | -B, --listen-addr6 listen ipv6 address, default: ::1 58 | -l, --listen-port listen port number, default: 60080 59 | -S, --tcp-syncnt change the number of tcp syn retransmits 60 | -c, --cache-size udp context cache maxsize, default: 256 61 | -o, --udp-timeout udp context idle timeout, default: 60 62 | -j, --thread-nums number of the worker threads, default: 1 63 | -n, --nofile-limit set nofile limit, may need root privilege 64 | -u, --run-user run as the given user, need root privilege 65 | -T, --tcp-only listen tcp only, aka: disable udp proxy 66 | -U, --udp-only listen udp only, aka: disable tcp proxy 67 | -4, --ipv4-only listen ipv4 only, aka: disable ipv6 proxy 68 | -6, --ipv6-only listen ipv6 only, aka: disable ipv4 proxy 69 | -R, --redirect use redirect instead of tproxy for tcp 70 | -r, --reuse-port enable so_reuseport for single thread 71 | -w, --tfo-accept enable tcp_fastopen for server socket 72 | -W, --tfo-connect enable tcp_fastopen for client socket 73 | -v, --verbose print verbose log, affect performance 74 | -V, --version print ipt2socks version number and exit 75 | -h, --help print ipt2socks help information and exit 76 | ``` 77 | 78 | - `-s`选项:socks5 服务器的 IP 地址,默认为 127.0.0.1。 79 | - `-p`选项:socks5 服务器的监听端口,默认为 1080。 80 | - `-a`选项:socks5 代理认证的用户(若需要认证)。 81 | - `-k`选项:socks5 代理认证的密码(若需要认证)。 82 | - `-b`选项:本地 IPv4 监听地址,默认为 127.0.0.1。 83 | - `-B`选项:本地 IPv6 监听地址,默认为 ::1。 84 | - `-l`选项:本地 IPv4/6 监听端口,默认为 60080。 85 | - `-S`选项:与 socks5 服务器建立 TCP 连接的超时参数。 86 | - `-c`选项:UDP 上下文的最大数量,默认为 256 个。 87 | - `-o`选项:UDP 上下文的超时时间,默认为 60 秒。 88 | - `-j`选项:需要启动的工作线程数量,默认为单个线程。 89 | - `-n`选项:设置 ipt2socks 进程可打开的文件描述符限制。 90 | - `-u`选项:即 run-as-user 功能,需要 root 权限才能生效。 91 | - `-T`选项:仅启用 TCP 透明代理,也即关闭 UDP 透明代理。 92 | - `-U`选项:仅启用 UDP 透明代理,也即关闭 TCP 透明代理。 93 | - `-4`选项:仅启用 IPv4 透明代理,也即关闭 IPv6 透明代理。 94 | - `-6`选项:仅启用 IPv6 透明代理,也即关闭 IPv4 透明代理。 95 | - `-R`选项:使用 REDIRECT(DNAT) 而非 TPROXY(针对 TCP)。 96 | - `-r`选项:若指定,则即使是单线程模式,也设置端口重用。 97 | - `-w`选项:启用服务端的 TCP_Fast_Open(应设好内核参数)。 98 | - `-W`选项:启用客户端的 TCP_Fast_Open(应设好内核参数)。 99 | - `-v`选项:若指定此选项,则将会打印较为详尽的运行时日志。 100 | 101 | ## 以普通用户运行 102 | 103 | - `sudo setcap cap_net_bind_service,cap_net_admin+ep /usr/local/bin/ipt2socks` 104 | - 如果以 root 用户启动 ipt2socks,也可以指定 `-u nobody` 选项切换至 `nobody` 用户 105 | 106 | ## nofile limit 107 | 108 | 由于透明代理需要消耗较多文件描述符,为确保最佳体验,请务必留意 ipt2socks 的 nofile limit(可同时打开的文件描述符数量),默认的 nofile limit 非常小,对于透明代理场景基本是不够用的。 109 | 110 | 从 v1.1.4 版本开始,ipt2socks 启动时将打印进程的 nofile limit 信息,请确保这个值至少在 10000 以上(很多系统默认是 1024),你可以选择使用 `-n` 选项调整此限制(需要 CAP_SYS_RESOURCE 权限),也可以使用其他方式,如 systemd service 文件的 `LimitNOFILE`、`/etc/security/limits.conf` 配置文件。 111 | -------------------------------------------------------------------------------- /ipt2socks.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=ipt2socks 3 | Requires=network.target network-online.target 4 | After=network.target network-online.target 5 | 6 | [Service] 7 | Type=simple 8 | Restart=always 9 | ExecStart=/usr/local/bin/ipt2socks -s 127.0.0.1 -p 61080 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | -------------------------------------------------------------------------------- /libev/config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #pragma GCC diagnostic ignored "-Wcomment" 4 | #pragma GCC diagnostic ignored "-Wunused-function" 5 | #pragma GCC diagnostic ignored "-Wunused-parameter" 6 | #pragma GCC diagnostic ignored "-Wunused-variable" 7 | #pragma GCC diagnostic ignored "-Wunused-value" 8 | #pragma GCC diagnostic ignored "-Wsign-compare" 9 | #ifdef __clang__ 10 | #pragma GCC diagnostic ignored "-Wextern-initializer" 11 | #endif 12 | 13 | /* libev-4.33 */ 14 | #define EV_STANDALONE 1 /* manual configuration */ 15 | #define EV_COMPAT3 0 /* remove compatible code */ 16 | #define EV_VERIFY 0 /* remove verification code */ 17 | #define EV_USE_FLOOR 1 /* use libm.floor() function */ 18 | #define EV_NO_SMP 1 /* disable multi-threads support */ 19 | #define EV_NO_THREADS 1 /* disable multi-threads support */ 20 | #define EV_PERIODIC_ENABLE 0 /* disable ev_periodic watcher */ 21 | #define EV_SIGNAL_ENABLE 0 /* disable ev_signal watcher */ 22 | #define EV_CHILD_ENABLE 0 /* disable ev_child watcher */ 23 | #define EV_STAT_ENABLE 0 /* disable ev_stat watcher */ 24 | #define EV_IDLE_ENABLE 0 /* disable ev_idle watcher */ 25 | #define EV_PREPARE_ENABLE 0 /* disable ev_prepare watcher */ 26 | #define EV_CHECK_ENABLE 0 /* disable ev_check watcher */ 27 | #define EV_EMBED_ENABLE 0 /* disable ev_embed watcher */ 28 | #define EV_FORK_ENABLE 0 /* disable ev_fork watcher */ 29 | #define EV_CLEANUP_ENABLE 0 /* disable ev_cleanup watcher */ 30 | #define EV_ASYNC_ENABLE 0 /* disbale ev_async watcher */ 31 | 32 | #define EV_USE_SELECT 0 33 | #define EV_USE_POLL 0 34 | #define EV_USE_EPOLL 1 35 | #define EV_USE_LINUXAIO 0 36 | #define EV_USE_IOURING 0 37 | #define EV_USE_KQUEUE 0 38 | #define EV_USE_PORT 0 39 | #define EV_USE_INOTIFY 0 40 | 41 | #define EV_MINPRI 0 42 | #define EV_MAXPRI 0 43 | 44 | /* typedef struct */ 45 | typedef struct ev_loop evloop_t; 46 | typedef struct ev_io evio_t; 47 | typedef struct ev_timer evtimer_t; 48 | 49 | /* typedef callback */ 50 | typedef void (*evio_cb_t)(evloop_t *evloop, evio_t *watcher, int revents); 51 | typedef void (*evtimer_cb_t)(evloop_t *evloop, evtimer_t *watcher, int revents); 52 | -------------------------------------------------------------------------------- /libev/ev.h: -------------------------------------------------------------------------------- 1 | /* 2 | * libev native API header 3 | * 4 | * Copyright (c) 2007-2020 Marc Alexander Lehmann 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modifica- 8 | * tion, are permitted provided that the following conditions are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- 19 | * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 20 | * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- 21 | * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- 25 | * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | * OF THE POSSIBILITY OF SUCH DAMAGE. 27 | * 28 | * Alternatively, the contents of this file may be used under the terms of 29 | * the GNU General Public License ("GPL") version 2 or any later version, 30 | * in which case the provisions of the GPL are applicable instead of 31 | * the above. If you wish to allow the use of your version of this file 32 | * only under the terms of the GPL and not to allow others to use your 33 | * version of this file under the BSD license, indicate your decision 34 | * by deleting the provisions above and replace them with the notice 35 | * and other provisions required by the GPL. If you do not delete the 36 | * provisions above, a recipient may use your version of this file under 37 | * either the BSD or the GPL. 38 | */ 39 | 40 | #ifndef EV_H_ 41 | #define EV_H_ 42 | 43 | #include "config.h" 44 | 45 | #ifdef __cplusplus 46 | # define EV_CPP(x) x 47 | # if __cplusplus >= 201103L 48 | # define EV_NOEXCEPT noexcept 49 | # else 50 | # define EV_NOEXCEPT 51 | # endif 52 | #else 53 | # define EV_CPP(x) 54 | # define EV_NOEXCEPT 55 | #endif 56 | #define EV_THROW EV_NOEXCEPT /* pre-4.25, do not use in new code */ 57 | 58 | EV_CPP(extern "C" {) 59 | 60 | /*****************************************************************************/ 61 | 62 | /* pre-4.0 compatibility */ 63 | #ifndef EV_COMPAT3 64 | # define EV_COMPAT3 1 65 | #endif 66 | 67 | #ifndef EV_FEATURES 68 | # if defined __OPTIMIZE_SIZE__ 69 | # define EV_FEATURES 0x7c 70 | # else 71 | # define EV_FEATURES 0x7f 72 | # endif 73 | #endif 74 | 75 | #define EV_FEATURE_CODE ((EV_FEATURES) & 1) 76 | #define EV_FEATURE_DATA ((EV_FEATURES) & 2) 77 | #define EV_FEATURE_CONFIG ((EV_FEATURES) & 4) 78 | #define EV_FEATURE_API ((EV_FEATURES) & 8) 79 | #define EV_FEATURE_WATCHERS ((EV_FEATURES) & 16) 80 | #define EV_FEATURE_BACKENDS ((EV_FEATURES) & 32) 81 | #define EV_FEATURE_OS ((EV_FEATURES) & 64) 82 | 83 | /* these priorities are inclusive, higher priorities will be invoked earlier */ 84 | #ifndef EV_MINPRI 85 | # define EV_MINPRI (EV_FEATURE_CONFIG ? -2 : 0) 86 | #endif 87 | #ifndef EV_MAXPRI 88 | # define EV_MAXPRI (EV_FEATURE_CONFIG ? +2 : 0) 89 | #endif 90 | 91 | #ifndef EV_MULTIPLICITY 92 | # define EV_MULTIPLICITY EV_FEATURE_CONFIG 93 | #endif 94 | 95 | #ifndef EV_PERIODIC_ENABLE 96 | # define EV_PERIODIC_ENABLE EV_FEATURE_WATCHERS 97 | #endif 98 | 99 | #ifndef EV_STAT_ENABLE 100 | # define EV_STAT_ENABLE EV_FEATURE_WATCHERS 101 | #endif 102 | 103 | #ifndef EV_PREPARE_ENABLE 104 | # define EV_PREPARE_ENABLE EV_FEATURE_WATCHERS 105 | #endif 106 | 107 | #ifndef EV_CHECK_ENABLE 108 | # define EV_CHECK_ENABLE EV_FEATURE_WATCHERS 109 | #endif 110 | 111 | #ifndef EV_IDLE_ENABLE 112 | # define EV_IDLE_ENABLE EV_FEATURE_WATCHERS 113 | #endif 114 | 115 | #ifndef EV_FORK_ENABLE 116 | # define EV_FORK_ENABLE EV_FEATURE_WATCHERS 117 | #endif 118 | 119 | #ifndef EV_CLEANUP_ENABLE 120 | # define EV_CLEANUP_ENABLE EV_FEATURE_WATCHERS 121 | #endif 122 | 123 | #ifndef EV_SIGNAL_ENABLE 124 | # define EV_SIGNAL_ENABLE EV_FEATURE_WATCHERS 125 | #endif 126 | 127 | #ifndef EV_CHILD_ENABLE 128 | # ifdef _WIN32 129 | # define EV_CHILD_ENABLE 0 130 | # else 131 | # define EV_CHILD_ENABLE EV_FEATURE_WATCHERS 132 | #endif 133 | #endif 134 | 135 | #ifndef EV_ASYNC_ENABLE 136 | # define EV_ASYNC_ENABLE EV_FEATURE_WATCHERS 137 | #endif 138 | 139 | #ifndef EV_EMBED_ENABLE 140 | # define EV_EMBED_ENABLE EV_FEATURE_WATCHERS 141 | #endif 142 | 143 | #ifndef EV_WALK_ENABLE 144 | # define EV_WALK_ENABLE 0 /* not yet */ 145 | #endif 146 | 147 | /*****************************************************************************/ 148 | 149 | #if EV_CHILD_ENABLE && !EV_SIGNAL_ENABLE 150 | # undef EV_SIGNAL_ENABLE 151 | # define EV_SIGNAL_ENABLE 1 152 | #endif 153 | 154 | /*****************************************************************************/ 155 | 156 | #ifndef EV_TSTAMP_T 157 | # define EV_TSTAMP_T double 158 | #endif 159 | typedef EV_TSTAMP_T ev_tstamp; 160 | 161 | #include /* for memmove */ 162 | 163 | #ifndef EV_ATOMIC_T 164 | # include 165 | # define EV_ATOMIC_T sig_atomic_t volatile 166 | #endif 167 | 168 | #if EV_STAT_ENABLE 169 | # ifdef _WIN32 170 | # include 171 | # include 172 | # endif 173 | # include 174 | #endif 175 | 176 | /* support multiple event loops? */ 177 | #if EV_MULTIPLICITY 178 | struct ev_loop; 179 | # define EV_P struct ev_loop *loop /* a loop as sole parameter in a declaration */ 180 | # define EV_P_ EV_P, /* a loop as first of multiple parameters */ 181 | # define EV_A loop /* a loop as sole argument to a function call */ 182 | # define EV_A_ EV_A, /* a loop as first of multiple arguments */ 183 | # define EV_DEFAULT_UC ev_default_loop_uc_ () /* the default loop, if initialised, as sole arg */ 184 | # define EV_DEFAULT_UC_ EV_DEFAULT_UC, /* the default loop as first of multiple arguments */ 185 | # define EV_DEFAULT ev_default_loop (0) /* the default loop as sole arg */ 186 | # define EV_DEFAULT_ EV_DEFAULT, /* the default loop as first of multiple arguments */ 187 | #else 188 | # define EV_P void 189 | # define EV_P_ 190 | # define EV_A 191 | # define EV_A_ 192 | # define EV_DEFAULT 193 | # define EV_DEFAULT_ 194 | # define EV_DEFAULT_UC 195 | # define EV_DEFAULT_UC_ 196 | # undef EV_EMBED_ENABLE 197 | #endif 198 | 199 | /* EV_INLINE is used for functions in header files */ 200 | #if __STDC_VERSION__ >= 199901L || __GNUC__ >= 3 201 | # define EV_INLINE static inline 202 | #else 203 | # define EV_INLINE static 204 | #endif 205 | 206 | #ifdef EV_API_STATIC 207 | # define EV_API_DECL static 208 | #else 209 | # define EV_API_DECL extern 210 | #endif 211 | 212 | /* EV_PROTOTYPES can be used to switch of prototype declarations */ 213 | #ifndef EV_PROTOTYPES 214 | # define EV_PROTOTYPES 1 215 | #endif 216 | 217 | /*****************************************************************************/ 218 | 219 | #define EV_VERSION_MAJOR 4 220 | #define EV_VERSION_MINOR 33 221 | 222 | /* eventmask, revents, events... */ 223 | enum { 224 | EV_UNDEF = (int)0xFFFFFFFF, /* guaranteed to be invalid */ 225 | EV_NONE = 0x00, /* no events */ 226 | EV_READ = 0x01, /* ev_io detected read will not block */ 227 | EV_WRITE = 0x02, /* ev_io detected write will not block */ 228 | EV__IOFDSET = 0x80, /* internal use only */ 229 | EV_IO = EV_READ, /* alias for type-detection */ 230 | EV_TIMER = 0x00000100, /* timer timed out */ 231 | #if EV_COMPAT3 232 | EV_TIMEOUT = EV_TIMER, /* pre 4.0 API compatibility */ 233 | #endif 234 | EV_PERIODIC = 0x00000200, /* periodic timer timed out */ 235 | EV_SIGNAL = 0x00000400, /* signal was received */ 236 | EV_CHILD = 0x00000800, /* child/pid had status change */ 237 | EV_STAT = 0x00001000, /* stat data changed */ 238 | EV_IDLE = 0x00002000, /* event loop is idling */ 239 | EV_PREPARE = 0x00004000, /* event loop about to poll */ 240 | EV_CHECK = 0x00008000, /* event loop finished poll */ 241 | EV_EMBED = 0x00010000, /* embedded event loop needs sweep */ 242 | EV_FORK = 0x00020000, /* event loop resumed in child */ 243 | EV_CLEANUP = 0x00040000, /* event loop resumed in child */ 244 | EV_ASYNC = 0x00080000, /* async intra-loop signal */ 245 | EV_CUSTOM = 0x01000000, /* for use by user code */ 246 | EV_ERROR = (int)0x80000000 /* sent when an error occurs */ 247 | }; 248 | 249 | /* can be used to add custom fields to all watchers, while losing binary compatibility */ 250 | #ifndef EV_COMMON 251 | # define EV_COMMON void *data; 252 | #endif 253 | 254 | #ifndef EV_CB_DECLARE 255 | # define EV_CB_DECLARE(type) void (*cb)(EV_P_ struct type *w, int revents); 256 | #endif 257 | #ifndef EV_CB_INVOKE 258 | # define EV_CB_INVOKE(watcher,revents) (watcher)->cb (EV_A_ (watcher), (revents)) 259 | #endif 260 | 261 | /* not official, do not use */ 262 | #define EV_CB(type,name) void name (EV_P_ struct ev_ ## type *w, int revents) 263 | 264 | /* 265 | * struct member types: 266 | * private: you may look at them, but not change them, 267 | * and they might not mean anything to you. 268 | * ro: can be read anytime, but only changed when the watcher isn't active. 269 | * rw: can be read and modified anytime, even when the watcher is active. 270 | * 271 | * some internal details that might be helpful for debugging: 272 | * 273 | * active is either 0, which means the watcher is not active, 274 | * or the array index of the watcher (periodics, timers) 275 | * or the array index + 1 (most other watchers) 276 | * or simply 1 for watchers that aren't in some array. 277 | * pending is either 0, in which case the watcher isn't, 278 | * or the array index + 1 in the pendings array. 279 | */ 280 | 281 | #if EV_MINPRI == EV_MAXPRI 282 | # define EV_DECL_PRIORITY 283 | #elif !defined (EV_DECL_PRIORITY) 284 | # define EV_DECL_PRIORITY int priority; 285 | #endif 286 | 287 | /* shared by all watchers */ 288 | #define EV_WATCHER(type) \ 289 | int active; /* private */ \ 290 | int pending; /* private */ \ 291 | EV_DECL_PRIORITY /* private */ \ 292 | EV_COMMON /* rw */ \ 293 | EV_CB_DECLARE (type) /* private */ 294 | 295 | #define EV_WATCHER_LIST(type) \ 296 | EV_WATCHER (type) \ 297 | struct ev_watcher_list *next; /* private */ 298 | 299 | #define EV_WATCHER_TIME(type) \ 300 | EV_WATCHER (type) \ 301 | ev_tstamp at; /* private */ 302 | 303 | /* base class, nothing to see here unless you subclass */ 304 | typedef struct ev_watcher 305 | { 306 | EV_WATCHER (ev_watcher) 307 | } ev_watcher; 308 | 309 | /* base class, nothing to see here unless you subclass */ 310 | typedef struct ev_watcher_list 311 | { 312 | EV_WATCHER_LIST (ev_watcher_list) 313 | } ev_watcher_list; 314 | 315 | /* base class, nothing to see here unless you subclass */ 316 | typedef struct ev_watcher_time 317 | { 318 | EV_WATCHER_TIME (ev_watcher_time) 319 | } ev_watcher_time; 320 | 321 | /* invoked when fd is either EV_READable or EV_WRITEable */ 322 | /* revent EV_READ, EV_WRITE */ 323 | typedef struct ev_io 324 | { 325 | EV_WATCHER_LIST (ev_io) 326 | 327 | int fd; /* ro */ 328 | int events; /* ro */ 329 | } ev_io; 330 | 331 | /* invoked after a specific time, repeatable (based on monotonic clock) */ 332 | /* revent EV_TIMEOUT */ 333 | typedef struct ev_timer 334 | { 335 | EV_WATCHER_TIME (ev_timer) 336 | 337 | ev_tstamp repeat; /* rw */ 338 | } ev_timer; 339 | 340 | /* invoked at some specific time, possibly repeating at regular intervals (based on UTC) */ 341 | /* revent EV_PERIODIC */ 342 | typedef struct ev_periodic 343 | { 344 | EV_WATCHER_TIME (ev_periodic) 345 | 346 | ev_tstamp offset; /* rw */ 347 | ev_tstamp interval; /* rw */ 348 | ev_tstamp (*reschedule_cb)(struct ev_periodic *w, ev_tstamp now) EV_NOEXCEPT; /* rw */ 349 | } ev_periodic; 350 | 351 | /* invoked when the given signal has been received */ 352 | /* revent EV_SIGNAL */ 353 | typedef struct ev_signal 354 | { 355 | EV_WATCHER_LIST (ev_signal) 356 | 357 | int signum; /* ro */ 358 | } ev_signal; 359 | 360 | /* invoked when sigchld is received and waitpid indicates the given pid */ 361 | /* revent EV_CHILD */ 362 | /* does not support priorities */ 363 | typedef struct ev_child 364 | { 365 | EV_WATCHER_LIST (ev_child) 366 | 367 | int flags; /* private */ 368 | int pid; /* ro */ 369 | int rpid; /* rw, holds the received pid */ 370 | int rstatus; /* rw, holds the exit status, use the macros from sys/wait.h */ 371 | } ev_child; 372 | 373 | #if EV_STAT_ENABLE 374 | /* st_nlink = 0 means missing file or other error */ 375 | # ifdef _WIN32 376 | typedef struct _stati64 ev_statdata; 377 | # else 378 | typedef struct stat ev_statdata; 379 | # endif 380 | 381 | /* invoked each time the stat data changes for a given path */ 382 | /* revent EV_STAT */ 383 | typedef struct ev_stat 384 | { 385 | EV_WATCHER_LIST (ev_stat) 386 | 387 | ev_timer timer; /* private */ 388 | ev_tstamp interval; /* ro */ 389 | const char *path; /* ro */ 390 | ev_statdata prev; /* ro */ 391 | ev_statdata attr; /* ro */ 392 | 393 | int wd; /* wd for inotify, fd for kqueue */ 394 | } ev_stat; 395 | #endif 396 | 397 | /* invoked when the nothing else needs to be done, keeps the process from blocking */ 398 | /* revent EV_IDLE */ 399 | typedef struct ev_idle 400 | { 401 | EV_WATCHER (ev_idle) 402 | } ev_idle; 403 | 404 | /* invoked for each run of the mainloop, just before the blocking call */ 405 | /* you can still change events in any way you like */ 406 | /* revent EV_PREPARE */ 407 | typedef struct ev_prepare 408 | { 409 | EV_WATCHER (ev_prepare) 410 | } ev_prepare; 411 | 412 | /* invoked for each run of the mainloop, just after the blocking call */ 413 | /* revent EV_CHECK */ 414 | typedef struct ev_check 415 | { 416 | EV_WATCHER (ev_check) 417 | } ev_check; 418 | 419 | /* the callback gets invoked before check in the child process when a fork was detected */ 420 | /* revent EV_FORK */ 421 | typedef struct ev_fork 422 | { 423 | EV_WATCHER (ev_fork) 424 | } ev_fork; 425 | 426 | /* is invoked just before the loop gets destroyed */ 427 | /* revent EV_CLEANUP */ 428 | typedef struct ev_cleanup 429 | { 430 | EV_WATCHER (ev_cleanup) 431 | } ev_cleanup; 432 | 433 | #if EV_EMBED_ENABLE 434 | /* used to embed an event loop inside another */ 435 | /* the callback gets invoked when the event loop has handled events, and can be 0 */ 436 | typedef struct ev_embed 437 | { 438 | EV_WATCHER (ev_embed) 439 | 440 | struct ev_loop *other; /* ro */ 441 | #undef EV_IO_ENABLE 442 | #define EV_IO_ENABLE 1 443 | ev_io io; /* private */ 444 | #undef EV_PREPARE_ENABLE 445 | #define EV_PREPARE_ENABLE 1 446 | ev_prepare prepare; /* private */ 447 | ev_check check; /* unused */ 448 | ev_timer timer; /* unused */ 449 | ev_periodic periodic; /* unused */ 450 | ev_idle idle; /* unused */ 451 | ev_fork fork; /* private */ 452 | ev_cleanup cleanup; /* unused */ 453 | } ev_embed; 454 | #endif 455 | 456 | #if EV_ASYNC_ENABLE 457 | /* invoked when somebody calls ev_async_send on the watcher */ 458 | /* revent EV_ASYNC */ 459 | typedef struct ev_async 460 | { 461 | EV_WATCHER (ev_async) 462 | 463 | EV_ATOMIC_T sent; /* private */ 464 | } ev_async; 465 | 466 | # define ev_async_pending(w) (+(w)->sent) 467 | #endif 468 | 469 | /* the presence of this union forces similar struct layout */ 470 | union ev_any_watcher 471 | { 472 | struct ev_watcher w; 473 | struct ev_watcher_list wl; 474 | 475 | struct ev_io io; 476 | struct ev_timer timer; 477 | struct ev_periodic periodic; 478 | struct ev_signal signal; 479 | struct ev_child child; 480 | #if EV_STAT_ENABLE 481 | struct ev_stat stat; 482 | #endif 483 | #if EV_IDLE_ENABLE 484 | struct ev_idle idle; 485 | #endif 486 | struct ev_prepare prepare; 487 | struct ev_check check; 488 | #if EV_FORK_ENABLE 489 | struct ev_fork fork; 490 | #endif 491 | #if EV_CLEANUP_ENABLE 492 | struct ev_cleanup cleanup; 493 | #endif 494 | #if EV_EMBED_ENABLE 495 | struct ev_embed embed; 496 | #endif 497 | #if EV_ASYNC_ENABLE 498 | struct ev_async async; 499 | #endif 500 | }; 501 | 502 | /* flag bits for ev_default_loop and ev_loop_new */ 503 | enum { 504 | /* the default */ 505 | EVFLAG_AUTO = 0x00000000U, /* not quite a mask */ 506 | /* flag bits */ 507 | EVFLAG_NOENV = 0x01000000U, /* do NOT consult environment */ 508 | EVFLAG_FORKCHECK = 0x02000000U, /* check for a fork in each iteration */ 509 | /* debugging/feature disable */ 510 | EVFLAG_NOINOTIFY = 0x00100000U, /* do not attempt to use inotify */ 511 | #if EV_COMPAT3 512 | EVFLAG_NOSIGFD = 0, /* compatibility to pre-3.9 */ 513 | #endif 514 | EVFLAG_SIGNALFD = 0x00200000U, /* attempt to use signalfd */ 515 | EVFLAG_NOSIGMASK = 0x00400000U, /* avoid modifying the signal mask */ 516 | EVFLAG_NOTIMERFD = 0x00800000U /* avoid creating a timerfd */ 517 | }; 518 | 519 | /* method bits to be ored together */ 520 | enum { 521 | EVBACKEND_SELECT = 0x00000001U, /* available just about anywhere */ 522 | EVBACKEND_POLL = 0x00000002U, /* !win, !aix, broken on osx */ 523 | EVBACKEND_EPOLL = 0x00000004U, /* linux */ 524 | EVBACKEND_KQUEUE = 0x00000008U, /* bsd, broken on osx */ 525 | EVBACKEND_DEVPOLL = 0x00000010U, /* solaris 8 */ /* NYI */ 526 | EVBACKEND_PORT = 0x00000020U, /* solaris 10 */ 527 | EVBACKEND_LINUXAIO = 0x00000040U, /* linux AIO, 4.19+ */ 528 | EVBACKEND_IOURING = 0x00000080U, /* linux io_uring, 5.1+ */ 529 | EVBACKEND_ALL = 0x000000FFU, /* all known backends */ 530 | EVBACKEND_MASK = 0x0000FFFFU /* all future backends */ 531 | }; 532 | 533 | #if EV_PROTOTYPES 534 | EV_API_DECL int ev_version_major (void) EV_NOEXCEPT; 535 | EV_API_DECL int ev_version_minor (void) EV_NOEXCEPT; 536 | 537 | EV_API_DECL unsigned int ev_supported_backends (void) EV_NOEXCEPT; 538 | EV_API_DECL unsigned int ev_recommended_backends (void) EV_NOEXCEPT; 539 | EV_API_DECL unsigned int ev_embeddable_backends (void) EV_NOEXCEPT; 540 | 541 | EV_API_DECL ev_tstamp ev_time (void) EV_NOEXCEPT; 542 | EV_API_DECL void ev_sleep (ev_tstamp delay) EV_NOEXCEPT; /* sleep for a while */ 543 | 544 | /* Sets the allocation function to use, works like realloc. 545 | * It is used to allocate and free memory. 546 | * If it returns zero when memory needs to be allocated, the library might abort 547 | * or take some potentially destructive action. 548 | * The default is your system realloc function. 549 | */ 550 | EV_API_DECL void ev_set_allocator (void *(*cb)(void *ptr, long size) EV_NOEXCEPT) EV_NOEXCEPT; 551 | 552 | /* set the callback function to call on a 553 | * retryable syscall error 554 | * (such as failed select, poll, epoll_wait) 555 | */ 556 | EV_API_DECL void ev_set_syserr_cb (void (*cb)(const char *msg) EV_NOEXCEPT) EV_NOEXCEPT; 557 | 558 | #if EV_MULTIPLICITY 559 | 560 | /* the default loop is the only one that handles signals and child watchers */ 561 | /* you can call this as often as you like */ 562 | EV_API_DECL struct ev_loop *ev_default_loop (unsigned int flags EV_CPP (= 0)) EV_NOEXCEPT; 563 | 564 | #ifdef EV_API_STATIC 565 | EV_API_DECL struct ev_loop *ev_default_loop_ptr; 566 | #endif 567 | 568 | EV_INLINE struct ev_loop * 569 | ev_default_loop_uc_ (void) EV_NOEXCEPT 570 | { 571 | extern struct ev_loop *ev_default_loop_ptr; 572 | 573 | return ev_default_loop_ptr; 574 | } 575 | 576 | EV_INLINE int 577 | ev_is_default_loop (EV_P) EV_NOEXCEPT 578 | { 579 | return EV_A == EV_DEFAULT_UC; 580 | } 581 | 582 | /* create and destroy alternative loops that don't handle signals */ 583 | EV_API_DECL struct ev_loop *ev_loop_new (unsigned int flags EV_CPP (= 0)) EV_NOEXCEPT; 584 | 585 | EV_API_DECL ev_tstamp ev_now (EV_P) EV_NOEXCEPT; /* time w.r.t. timers and the eventloop, updated after each poll */ 586 | 587 | #else 588 | 589 | EV_API_DECL int ev_default_loop (unsigned int flags EV_CPP (= 0)) EV_NOEXCEPT; /* returns true when successful */ 590 | 591 | EV_API_DECL ev_tstamp ev_rt_now; 592 | 593 | EV_INLINE ev_tstamp 594 | ev_now (void) EV_NOEXCEPT 595 | { 596 | return ev_rt_now; 597 | } 598 | 599 | /* looks weird, but ev_is_default_loop (EV_A) still works if this exists */ 600 | EV_INLINE int 601 | ev_is_default_loop (void) EV_NOEXCEPT 602 | { 603 | return 1; 604 | } 605 | 606 | #endif /* multiplicity */ 607 | 608 | /* destroy event loops, also works for the default loop */ 609 | EV_API_DECL void ev_loop_destroy (EV_P); 610 | 611 | /* this needs to be called after fork, to duplicate the loop */ 612 | /* when you want to re-use it in the child */ 613 | /* you can call it in either the parent or the child */ 614 | /* you can actually call it at any time, anywhere :) */ 615 | EV_API_DECL void ev_loop_fork (EV_P) EV_NOEXCEPT; 616 | 617 | EV_API_DECL unsigned int ev_backend (EV_P) EV_NOEXCEPT; /* backend in use by loop */ 618 | 619 | EV_API_DECL void ev_now_update (EV_P) EV_NOEXCEPT; /* update event loop time */ 620 | 621 | #if EV_WALK_ENABLE 622 | /* walk (almost) all watchers in the loop of a given type, invoking the */ 623 | /* callback on every such watcher. The callback might stop the watcher, */ 624 | /* but do nothing else with the loop */ 625 | EV_API_DECL void ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w)) EV_NOEXCEPT; 626 | #endif 627 | 628 | #endif /* prototypes */ 629 | 630 | /* ev_run flags values */ 631 | enum { 632 | EVRUN_NOWAIT = 1, /* do not block/wait */ 633 | EVRUN_ONCE = 2 /* block *once* only */ 634 | }; 635 | 636 | /* ev_break how values */ 637 | enum { 638 | EVBREAK_CANCEL = 0, /* undo unloop */ 639 | EVBREAK_ONE = 1, /* unloop once */ 640 | EVBREAK_ALL = 2 /* unloop all loops */ 641 | }; 642 | 643 | #if EV_PROTOTYPES 644 | EV_API_DECL int ev_run (EV_P_ int flags EV_CPP (= 0)); 645 | EV_API_DECL void ev_break (EV_P_ int how EV_CPP (= EVBREAK_ONE)) EV_NOEXCEPT; /* break out of the loop */ 646 | 647 | /* 648 | * ref/unref can be used to add or remove a refcount on the mainloop. every watcher 649 | * keeps one reference. if you have a long-running watcher you never unregister that 650 | * should not keep ev_loop from running, unref() after starting, and ref() before stopping. 651 | */ 652 | EV_API_DECL void ev_ref (EV_P) EV_NOEXCEPT; 653 | EV_API_DECL void ev_unref (EV_P) EV_NOEXCEPT; 654 | 655 | /* 656 | * convenience function, wait for a single event, without registering an event watcher 657 | * if timeout is < 0, do wait indefinitely 658 | */ 659 | EV_API_DECL void ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revents, void *arg), void *arg) EV_NOEXCEPT; 660 | 661 | EV_API_DECL void ev_invoke_pending (EV_P); /* invoke all pending watchers */ 662 | 663 | # if EV_FEATURE_API 664 | EV_API_DECL unsigned int ev_iteration (EV_P) EV_NOEXCEPT; /* number of loop iterations */ 665 | EV_API_DECL unsigned int ev_depth (EV_P) EV_NOEXCEPT; /* #ev_loop enters - #ev_loop leaves */ 666 | EV_API_DECL void ev_verify (EV_P) EV_NOEXCEPT; /* abort if loop data corrupted */ 667 | 668 | EV_API_DECL void ev_set_io_collect_interval (EV_P_ ev_tstamp interval) EV_NOEXCEPT; /* sleep at least this time, default 0 */ 669 | EV_API_DECL void ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval) EV_NOEXCEPT; /* sleep at least this time, default 0 */ 670 | 671 | /* advanced stuff for threading etc. support, see docs */ 672 | EV_API_DECL void ev_set_userdata (EV_P_ void *data) EV_NOEXCEPT; 673 | EV_API_DECL void *ev_userdata (EV_P) EV_NOEXCEPT; 674 | typedef void (*ev_loop_callback)(EV_P); 675 | EV_API_DECL void ev_set_invoke_pending_cb (EV_P_ ev_loop_callback invoke_pending_cb) EV_NOEXCEPT; 676 | /* C++ doesn't allow the use of the ev_loop_callback typedef here, so we need to spell it out */ 677 | EV_API_DECL void ev_set_loop_release_cb (EV_P_ void (*release)(EV_P) EV_NOEXCEPT, void (*acquire)(EV_P) EV_NOEXCEPT) EV_NOEXCEPT; 678 | 679 | EV_API_DECL unsigned int ev_pending_count (EV_P) EV_NOEXCEPT; /* number of pending events, if any */ 680 | 681 | /* 682 | * stop/start the timer handling. 683 | */ 684 | EV_API_DECL void ev_suspend (EV_P) EV_NOEXCEPT; 685 | EV_API_DECL void ev_resume (EV_P) EV_NOEXCEPT; 686 | #endif 687 | 688 | #endif 689 | 690 | /* these may evaluate ev multiple times, and the other arguments at most once */ 691 | /* either use ev_init + ev_TYPE_set, or the ev_TYPE_init macro, below, to first initialise a watcher */ 692 | #define ev_init(ev,cb_) do { \ 693 | ((ev_watcher *)(void *)(ev))->active = \ 694 | ((ev_watcher *)(void *)(ev))->pending = 0; \ 695 | ev_set_priority ((ev), 0); \ 696 | ev_set_cb ((ev), cb_); \ 697 | } while (0) 698 | 699 | #define ev_io_modify(ev,events_) do { (ev)->events = ((ev)->events & EV__IOFDSET) | (events_); } while (0) 700 | #define ev_io_set(ev,fd_,events_) do { (ev)->fd = (fd_); (ev)->events = (events_) | EV__IOFDSET; } while (0) 701 | #define ev_timer_set(ev,after_,repeat_) do { ((ev_watcher_time *)(ev))->at = (after_); (ev)->repeat = (repeat_); } while (0) 702 | #define ev_periodic_set(ev,ofs_,ival_,rcb_) do { (ev)->offset = (ofs_); (ev)->interval = (ival_); (ev)->reschedule_cb = (rcb_); } while (0) 703 | #define ev_signal_set(ev,signum_) do { (ev)->signum = (signum_); } while (0) 704 | #define ev_child_set(ev,pid_,trace_) do { (ev)->pid = (pid_); (ev)->flags = !!(trace_); } while (0) 705 | #define ev_stat_set(ev,path_,interval_) do { (ev)->path = (path_); (ev)->interval = (interval_); (ev)->wd = -2; } while (0) 706 | #define ev_idle_set(ev) /* nop, yes, this is a serious in-joke */ 707 | #define ev_prepare_set(ev) /* nop, yes, this is a serious in-joke */ 708 | #define ev_check_set(ev) /* nop, yes, this is a serious in-joke */ 709 | #define ev_embed_set(ev,other_) do { (ev)->other = (other_); } while (0) 710 | #define ev_fork_set(ev) /* nop, yes, this is a serious in-joke */ 711 | #define ev_cleanup_set(ev) /* nop, yes, this is a serious in-joke */ 712 | #define ev_async_set(ev) /* nop, yes, this is a serious in-joke */ 713 | 714 | #define ev_io_init(ev,cb,fd,events) do { ev_init ((ev), (cb)); ev_io_set ((ev),(fd),(events)); } while (0) 715 | #define ev_timer_init(ev,cb,after,repeat) do { ev_init ((ev), (cb)); ev_timer_set ((ev),(after),(repeat)); } while (0) 716 | #define ev_periodic_init(ev,cb,ofs,ival,rcb) do { ev_init ((ev), (cb)); ev_periodic_set ((ev),(ofs),(ival),(rcb)); } while (0) 717 | #define ev_signal_init(ev,cb,signum) do { ev_init ((ev), (cb)); ev_signal_set ((ev), (signum)); } while (0) 718 | #define ev_child_init(ev,cb,pid,trace) do { ev_init ((ev), (cb)); ev_child_set ((ev),(pid),(trace)); } while (0) 719 | #define ev_stat_init(ev,cb,path,interval) do { ev_init ((ev), (cb)); ev_stat_set ((ev),(path),(interval)); } while (0) 720 | #define ev_idle_init(ev,cb) do { ev_init ((ev), (cb)); ev_idle_set ((ev)); } while (0) 721 | #define ev_prepare_init(ev,cb) do { ev_init ((ev), (cb)); ev_prepare_set ((ev)); } while (0) 722 | #define ev_check_init(ev,cb) do { ev_init ((ev), (cb)); ev_check_set ((ev)); } while (0) 723 | #define ev_embed_init(ev,cb,other) do { ev_init ((ev), (cb)); ev_embed_set ((ev),(other)); } while (0) 724 | #define ev_fork_init(ev,cb) do { ev_init ((ev), (cb)); ev_fork_set ((ev)); } while (0) 725 | #define ev_cleanup_init(ev,cb) do { ev_init ((ev), (cb)); ev_cleanup_set ((ev)); } while (0) 726 | #define ev_async_init(ev,cb) do { ev_init ((ev), (cb)); ev_async_set ((ev)); } while (0) 727 | 728 | #define ev_is_pending(ev) (0 + ((ev_watcher *)(void *)(ev))->pending) /* ro, true when watcher is waiting for callback invocation */ 729 | #define ev_is_active(ev) (0 + ((ev_watcher *)(void *)(ev))->active) /* ro, true when the watcher has been started */ 730 | 731 | #define ev_cb_(ev) (ev)->cb /* rw */ 732 | #define ev_cb(ev) (memmove (&ev_cb_ (ev), &((ev_watcher *)(ev))->cb, sizeof (ev_cb_ (ev))), (ev)->cb) 733 | 734 | #if EV_MINPRI == EV_MAXPRI 735 | # define ev_priority(ev) ((ev), EV_MINPRI) 736 | # define ev_set_priority(ev,pri) ((ev), (pri)) 737 | #else 738 | # define ev_priority(ev) (+(((ev_watcher *)(void *)(ev))->priority)) 739 | # define ev_set_priority(ev,pri) ( (ev_watcher *)(void *)(ev))->priority = (pri) 740 | #endif 741 | 742 | #define ev_periodic_at(ev) (+((ev_watcher_time *)(ev))->at) 743 | 744 | #ifndef ev_set_cb 745 | /* memmove is used here to avoid strict aliasing violations, and hopefully is optimized out by any reasonable compiler */ 746 | # define ev_set_cb(ev,cb_) (ev_cb_ (ev) = (cb_), memmove (&((ev_watcher *)(ev))->cb, &ev_cb_ (ev), sizeof (ev_cb_ (ev)))) 747 | #endif 748 | 749 | /* stopping (enabling, adding) a watcher does nothing if it is already running */ 750 | /* stopping (disabling, deleting) a watcher does nothing unless it's already running */ 751 | #if EV_PROTOTYPES 752 | 753 | /* feeds an event into a watcher as if the event actually occurred */ 754 | /* accepts any ev_watcher type */ 755 | EV_API_DECL void ev_feed_event (EV_P_ void *w, int revents) EV_NOEXCEPT; 756 | EV_API_DECL void ev_feed_fd_event (EV_P_ int fd, int revents) EV_NOEXCEPT; 757 | #if EV_SIGNAL_ENABLE 758 | EV_API_DECL void ev_feed_signal (int signum) EV_NOEXCEPT; 759 | EV_API_DECL void ev_feed_signal_event (EV_P_ int signum) EV_NOEXCEPT; 760 | #endif 761 | EV_API_DECL void ev_invoke (EV_P_ void *w, int revents); 762 | EV_API_DECL int ev_clear_pending (EV_P_ void *w) EV_NOEXCEPT; 763 | 764 | EV_API_DECL void ev_io_start (EV_P_ ev_io *w) EV_NOEXCEPT; 765 | EV_API_DECL void ev_io_stop (EV_P_ ev_io *w) EV_NOEXCEPT; 766 | 767 | EV_API_DECL void ev_timer_start (EV_P_ ev_timer *w) EV_NOEXCEPT; 768 | EV_API_DECL void ev_timer_stop (EV_P_ ev_timer *w) EV_NOEXCEPT; 769 | /* stops if active and no repeat, restarts if active and repeating, starts if inactive and repeating */ 770 | EV_API_DECL void ev_timer_again (EV_P_ ev_timer *w) EV_NOEXCEPT; 771 | /* return remaining time */ 772 | EV_API_DECL ev_tstamp ev_timer_remaining (EV_P_ ev_timer *w) EV_NOEXCEPT; 773 | 774 | #if EV_PERIODIC_ENABLE 775 | EV_API_DECL void ev_periodic_start (EV_P_ ev_periodic *w) EV_NOEXCEPT; 776 | EV_API_DECL void ev_periodic_stop (EV_P_ ev_periodic *w) EV_NOEXCEPT; 777 | EV_API_DECL void ev_periodic_again (EV_P_ ev_periodic *w) EV_NOEXCEPT; 778 | #endif 779 | 780 | /* only supported in the default loop */ 781 | #if EV_SIGNAL_ENABLE 782 | EV_API_DECL void ev_signal_start (EV_P_ ev_signal *w) EV_NOEXCEPT; 783 | EV_API_DECL void ev_signal_stop (EV_P_ ev_signal *w) EV_NOEXCEPT; 784 | #endif 785 | 786 | /* only supported in the default loop */ 787 | # if EV_CHILD_ENABLE 788 | EV_API_DECL void ev_child_start (EV_P_ ev_child *w) EV_NOEXCEPT; 789 | EV_API_DECL void ev_child_stop (EV_P_ ev_child *w) EV_NOEXCEPT; 790 | # endif 791 | 792 | # if EV_STAT_ENABLE 793 | EV_API_DECL void ev_stat_start (EV_P_ ev_stat *w) EV_NOEXCEPT; 794 | EV_API_DECL void ev_stat_stop (EV_P_ ev_stat *w) EV_NOEXCEPT; 795 | EV_API_DECL void ev_stat_stat (EV_P_ ev_stat *w) EV_NOEXCEPT; 796 | # endif 797 | 798 | # if EV_IDLE_ENABLE 799 | EV_API_DECL void ev_idle_start (EV_P_ ev_idle *w) EV_NOEXCEPT; 800 | EV_API_DECL void ev_idle_stop (EV_P_ ev_idle *w) EV_NOEXCEPT; 801 | # endif 802 | 803 | #if EV_PREPARE_ENABLE 804 | EV_API_DECL void ev_prepare_start (EV_P_ ev_prepare *w) EV_NOEXCEPT; 805 | EV_API_DECL void ev_prepare_stop (EV_P_ ev_prepare *w) EV_NOEXCEPT; 806 | #endif 807 | 808 | #if EV_CHECK_ENABLE 809 | EV_API_DECL void ev_check_start (EV_P_ ev_check *w) EV_NOEXCEPT; 810 | EV_API_DECL void ev_check_stop (EV_P_ ev_check *w) EV_NOEXCEPT; 811 | #endif 812 | 813 | # if EV_FORK_ENABLE 814 | EV_API_DECL void ev_fork_start (EV_P_ ev_fork *w) EV_NOEXCEPT; 815 | EV_API_DECL void ev_fork_stop (EV_P_ ev_fork *w) EV_NOEXCEPT; 816 | # endif 817 | 818 | # if EV_CLEANUP_ENABLE 819 | EV_API_DECL void ev_cleanup_start (EV_P_ ev_cleanup *w) EV_NOEXCEPT; 820 | EV_API_DECL void ev_cleanup_stop (EV_P_ ev_cleanup *w) EV_NOEXCEPT; 821 | # endif 822 | 823 | # if EV_EMBED_ENABLE 824 | /* only supported when loop to be embedded is in fact embeddable */ 825 | EV_API_DECL void ev_embed_start (EV_P_ ev_embed *w) EV_NOEXCEPT; 826 | EV_API_DECL void ev_embed_stop (EV_P_ ev_embed *w) EV_NOEXCEPT; 827 | EV_API_DECL void ev_embed_sweep (EV_P_ ev_embed *w) EV_NOEXCEPT; 828 | # endif 829 | 830 | # if EV_ASYNC_ENABLE 831 | EV_API_DECL void ev_async_start (EV_P_ ev_async *w) EV_NOEXCEPT; 832 | EV_API_DECL void ev_async_stop (EV_P_ ev_async *w) EV_NOEXCEPT; 833 | EV_API_DECL void ev_async_send (EV_P_ ev_async *w) EV_NOEXCEPT; 834 | # endif 835 | 836 | #if EV_COMPAT3 837 | #define EVLOOP_NONBLOCK EVRUN_NOWAIT 838 | #define EVLOOP_ONESHOT EVRUN_ONCE 839 | #define EVUNLOOP_CANCEL EVBREAK_CANCEL 840 | #define EVUNLOOP_ONE EVBREAK_ONE 841 | #define EVUNLOOP_ALL EVBREAK_ALL 842 | #if EV_PROTOTYPES 843 | EV_INLINE void ev_loop (EV_P_ int flags) { ev_run (EV_A_ flags); } 844 | EV_INLINE void ev_unloop (EV_P_ int how ) { ev_break (EV_A_ how ); } 845 | EV_INLINE void ev_default_destroy (void) { ev_loop_destroy (EV_DEFAULT); } 846 | EV_INLINE void ev_default_fork (void) { ev_loop_fork (EV_DEFAULT); } 847 | #if EV_FEATURE_API 848 | EV_INLINE unsigned int ev_loop_count (EV_P) { return ev_iteration (EV_A); } 849 | EV_INLINE unsigned int ev_loop_depth (EV_P) { return ev_depth (EV_A); } 850 | EV_INLINE void ev_loop_verify (EV_P) { ev_verify (EV_A); } 851 | #endif 852 | #endif 853 | #else 854 | typedef struct ev_loop ev_loop; 855 | #endif 856 | 857 | #endif 858 | 859 | EV_CPP(}) 860 | 861 | #endif 862 | 863 | -------------------------------------------------------------------------------- /libev/ev_epoll.c: -------------------------------------------------------------------------------- 1 | /* 2 | * libev epoll fd activity backend 3 | * 4 | * Copyright (c) 2007,2008,2009,2010,2011,2016,2017,2019 Marc Alexander Lehmann 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modifica- 8 | * tion, are permitted provided that the following conditions are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- 19 | * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 20 | * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- 21 | * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- 25 | * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | * OF THE POSSIBILITY OF SUCH DAMAGE. 27 | * 28 | * Alternatively, the contents of this file may be used under the terms of 29 | * the GNU General Public License ("GPL") version 2 or any later version, 30 | * in which case the provisions of the GPL are applicable instead of 31 | * the above. If you wish to allow the use of your version of this file 32 | * only under the terms of the GPL and not to allow others to use your 33 | * version of this file under the BSD license, indicate your decision 34 | * by deleting the provisions above and replace them with the notice 35 | * and other provisions required by the GPL. If you do not delete the 36 | * provisions above, a recipient may use your version of this file under 37 | * either the BSD or the GPL. 38 | */ 39 | 40 | /* 41 | * general notes about epoll: 42 | * 43 | * a) epoll silently removes fds from the fd set. as nothing tells us 44 | * that an fd has been removed otherwise, we have to continually 45 | * "rearm" fds that we suspect *might* have changed (same 46 | * problem with kqueue, but much less costly there). 47 | * b) the fact that ADD != MOD creates a lot of extra syscalls due to a) 48 | * and seems not to have any advantage. 49 | * c) the inability to handle fork or file descriptors (think dup) 50 | * limits the applicability over poll, so this is not a generic 51 | * poll replacement. 52 | * d) epoll doesn't work the same as select with many file descriptors 53 | * (such as files). while not critical, no other advanced interface 54 | * seems to share this (rather non-unixy) limitation. 55 | * e) epoll claims to be embeddable, but in practise you never get 56 | * a ready event for the epoll fd (broken: <=2.6.26, working: >=2.6.32). 57 | * f) epoll_ctl returning EPERM means the fd is always ready. 58 | * 59 | * lots of "weird code" and complication handling in this file is due 60 | * to these design problems with epoll, as we try very hard to avoid 61 | * epoll_ctl syscalls for common usage patterns and handle the breakage 62 | * ensuing from receiving events for closed and otherwise long gone 63 | * file descriptors. 64 | */ 65 | 66 | #include 67 | 68 | #define EV_EMASK_EPERM 0x80 69 | 70 | static void 71 | epoll_modify (EV_P_ int fd, int oev, int nev) 72 | { 73 | struct epoll_event ev; 74 | unsigned char oldmask; 75 | 76 | /* 77 | * we handle EPOLL_CTL_DEL by ignoring it here 78 | * on the assumption that the fd is gone anyways 79 | * if that is wrong, we have to handle the spurious 80 | * event in epoll_poll. 81 | * if the fd is added again, we try to ADD it, and, if that 82 | * fails, we assume it still has the same eventmask. 83 | */ 84 | if (!nev) 85 | return; 86 | 87 | oldmask = anfds [fd].emask; 88 | anfds [fd].emask = nev; 89 | 90 | /* store the generation counter in the upper 32 bits, the fd in the lower 32 bits */ 91 | ev.data.u64 = (uint64_t)(uint32_t)fd 92 | | ((uint64_t)(uint32_t)++anfds [fd].egen << 32); 93 | ev.events = (nev & EV_READ ? EPOLLIN : 0) 94 | | (nev & EV_WRITE ? EPOLLOUT : 0); 95 | 96 | if (ecb_expect_true (!epoll_ctl (backend_fd, oev && oldmask != nev ? EPOLL_CTL_MOD : EPOLL_CTL_ADD, fd, &ev))) 97 | return; 98 | 99 | if (ecb_expect_true (errno == ENOENT)) 100 | { 101 | /* if ENOENT then the fd went away, so try to do the right thing */ 102 | if (!nev) 103 | goto dec_egen; 104 | 105 | if (!epoll_ctl (backend_fd, EPOLL_CTL_ADD, fd, &ev)) 106 | return; 107 | } 108 | else if (ecb_expect_true (errno == EEXIST)) 109 | { 110 | /* EEXIST means we ignored a previous DEL, but the fd is still active */ 111 | /* if the kernel mask is the same as the new mask, we assume it hasn't changed */ 112 | if (oldmask == nev) 113 | goto dec_egen; 114 | 115 | if (!epoll_ctl (backend_fd, EPOLL_CTL_MOD, fd, &ev)) 116 | return; 117 | } 118 | else if (ecb_expect_true (errno == EPERM)) 119 | { 120 | /* EPERM means the fd is always ready, but epoll is too snobbish */ 121 | /* to handle it, unlike select or poll. */ 122 | anfds [fd].emask = EV_EMASK_EPERM; 123 | 124 | /* add fd to epoll_eperms, if not already inside */ 125 | if (!(oldmask & EV_EMASK_EPERM)) 126 | { 127 | array_needsize (int, epoll_eperms, epoll_epermmax, epoll_epermcnt + 1, array_needsize_noinit); 128 | epoll_eperms [epoll_epermcnt++] = fd; 129 | } 130 | 131 | return; 132 | } 133 | else 134 | assert (("libev: I/O watcher with invalid fd found in epoll_ctl", errno != EBADF && errno != ELOOP && errno != EINVAL)); 135 | 136 | fd_kill (EV_A_ fd); 137 | 138 | dec_egen: 139 | /* we didn't successfully call epoll_ctl, so decrement the generation counter again */ 140 | --anfds [fd].egen; 141 | } 142 | 143 | static void 144 | epoll_poll (EV_P_ ev_tstamp timeout) 145 | { 146 | int i; 147 | int eventcnt; 148 | 149 | if (ecb_expect_false (epoll_epermcnt)) 150 | timeout = EV_TS_CONST (0.); 151 | 152 | /* epoll wait times cannot be larger than (LONG_MAX - 999UL) / HZ msecs, which is below */ 153 | /* the default libev max wait time, however. */ 154 | EV_RELEASE_CB; 155 | eventcnt = epoll_wait (backend_fd, epoll_events, epoll_eventmax, EV_TS_TO_MSEC (timeout)); 156 | EV_ACQUIRE_CB; 157 | 158 | if (ecb_expect_false (eventcnt < 0)) 159 | { 160 | if (errno != EINTR) 161 | ev_syserr ("(libev) epoll_wait"); 162 | 163 | return; 164 | } 165 | 166 | for (i = 0; i < eventcnt; ++i) 167 | { 168 | struct epoll_event *ev = epoll_events + i; 169 | 170 | int fd = (uint32_t)ev->data.u64; /* mask out the lower 32 bits */ 171 | int want = anfds [fd].events; 172 | int got = (ev->events & (EPOLLOUT | EPOLLERR | EPOLLHUP) ? EV_WRITE : 0) 173 | | (ev->events & (EPOLLIN | EPOLLERR | EPOLLHUP) ? EV_READ : 0); 174 | 175 | /* 176 | * check for spurious notification. 177 | * this only finds spurious notifications on egen updates 178 | * other spurious notifications will be found by epoll_ctl, below 179 | * we assume that fd is always in range, as we never shrink the anfds array 180 | */ 181 | if (ecb_expect_false ((uint32_t)anfds [fd].egen != (uint32_t)(ev->data.u64 >> 32))) 182 | { 183 | /* recreate kernel state */ 184 | postfork |= 2; 185 | continue; 186 | } 187 | 188 | if (ecb_expect_false (got & ~want)) 189 | { 190 | anfds [fd].emask = want; 191 | 192 | /* 193 | * we received an event but are not interested in it, try mod or del 194 | * this often happens because we optimistically do not unregister fds 195 | * when we are no longer interested in them, but also when we get spurious 196 | * notifications for fds from another process. this is partially handled 197 | * above with the gencounter check (== our fd is not the event fd), and 198 | * partially here, when epoll_ctl returns an error (== a child has the fd 199 | * but we closed it). 200 | * note: for events such as POLLHUP, where we can't know whether it refers 201 | * to EV_READ or EV_WRITE, we might issue redundant EPOLL_CTL_MOD calls. 202 | */ 203 | ev->events = (want & EV_READ ? EPOLLIN : 0) 204 | | (want & EV_WRITE ? EPOLLOUT : 0); 205 | 206 | /* pre-2.6.9 kernels require a non-null pointer with EPOLL_CTL_DEL, */ 207 | /* which is fortunately easy to do for us. */ 208 | if (epoll_ctl (backend_fd, want ? EPOLL_CTL_MOD : EPOLL_CTL_DEL, fd, ev)) 209 | { 210 | postfork |= 2; /* an error occurred, recreate kernel state */ 211 | continue; 212 | } 213 | } 214 | 215 | fd_event (EV_A_ fd, got); 216 | } 217 | 218 | /* if the receive array was full, increase its size */ 219 | if (ecb_expect_false (eventcnt == epoll_eventmax)) 220 | { 221 | ev_free (epoll_events); 222 | epoll_eventmax = array_nextsize (sizeof (struct epoll_event), epoll_eventmax, epoll_eventmax + 1); 223 | epoll_events = (struct epoll_event *)ev_malloc (sizeof (struct epoll_event) * epoll_eventmax); 224 | } 225 | 226 | /* now synthesize events for all fds where epoll fails, while select works... */ 227 | for (i = epoll_epermcnt; i--; ) 228 | { 229 | int fd = epoll_eperms [i]; 230 | unsigned char events = anfds [fd].events & (EV_READ | EV_WRITE); 231 | 232 | if (anfds [fd].emask & EV_EMASK_EPERM && events) 233 | fd_event (EV_A_ fd, events); 234 | else 235 | { 236 | epoll_eperms [i] = epoll_eperms [--epoll_epermcnt]; 237 | anfds [fd].emask = 0; 238 | } 239 | } 240 | } 241 | 242 | static int 243 | epoll_epoll_create (void) 244 | { 245 | int fd; 246 | 247 | #if defined EPOLL_CLOEXEC && !defined __ANDROID__ 248 | fd = epoll_create1 (EPOLL_CLOEXEC); 249 | 250 | if (fd < 0 && (errno == EINVAL || errno == ENOSYS)) 251 | #endif 252 | { 253 | fd = epoll_create (256); 254 | 255 | if (fd >= 0) 256 | fcntl (fd, F_SETFD, FD_CLOEXEC); 257 | } 258 | 259 | return fd; 260 | } 261 | 262 | inline_size 263 | int 264 | epoll_init (EV_P_ int flags) 265 | { 266 | if ((backend_fd = epoll_epoll_create ()) < 0) 267 | return 0; 268 | 269 | backend_mintime = EV_TS_CONST (1e-3); /* epoll does sometimes return early, this is just to avoid the worst */ 270 | backend_modify = epoll_modify; 271 | backend_poll = epoll_poll; 272 | 273 | epoll_eventmax = 64; /* initial number of events receivable per poll */ 274 | epoll_events = (struct epoll_event *)ev_malloc (sizeof (struct epoll_event) * epoll_eventmax); 275 | 276 | return EVBACKEND_EPOLL; 277 | } 278 | 279 | inline_size 280 | void 281 | epoll_destroy (EV_P) 282 | { 283 | ev_free (epoll_events); 284 | array_free (epoll_eperm, EMPTY); 285 | } 286 | 287 | ecb_cold 288 | static void 289 | epoll_fork (EV_P) 290 | { 291 | close (backend_fd); 292 | 293 | while ((backend_fd = epoll_epoll_create ()) < 0) 294 | ev_syserr ("(libev) epoll_create"); 295 | 296 | fd_rearm_all (EV_A); 297 | } 298 | 299 | -------------------------------------------------------------------------------- /libev/ev_vars.h: -------------------------------------------------------------------------------- 1 | /* 2 | * loop member variable declarations 3 | * 4 | * Copyright (c) 2007,2008,2009,2010,2011,2012,2013,2019 Marc Alexander Lehmann 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modifica- 8 | * tion, are permitted provided that the following conditions are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- 19 | * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 20 | * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- 21 | * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- 25 | * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | * OF THE POSSIBILITY OF SUCH DAMAGE. 27 | * 28 | * Alternatively, the contents of this file may be used under the terms of 29 | * the GNU General Public License ("GPL") version 2 or any later version, 30 | * in which case the provisions of the GPL are applicable instead of 31 | * the above. If you wish to allow the use of your version of this file 32 | * only under the terms of the GPL and not to allow others to use your 33 | * version of this file under the BSD license, indicate your decision 34 | * by deleting the provisions above and replace them with the notice 35 | * and other provisions required by the GPL. If you do not delete the 36 | * provisions above, a recipient may use your version of this file under 37 | * either the BSD or the GPL. 38 | */ 39 | 40 | #define VARx(type,name) VAR(name, type name) 41 | 42 | VARx(ev_tstamp, now_floor) /* last time we refreshed rt_time */ 43 | VARx(ev_tstamp, mn_now) /* monotonic clock "now" */ 44 | VARx(ev_tstamp, rtmn_diff) /* difference realtime - monotonic time */ 45 | 46 | /* for reverse feeding of events */ 47 | VARx(W *, rfeeds) 48 | VARx(int, rfeedmax) 49 | VARx(int, rfeedcnt) 50 | 51 | VAR (pendings, ANPENDING *pendings [NUMPRI]) 52 | VAR (pendingmax, int pendingmax [NUMPRI]) 53 | VAR (pendingcnt, int pendingcnt [NUMPRI]) 54 | VARx(int, pendingpri) /* highest priority currently pending */ 55 | VARx(ev_prepare, pending_w) /* dummy pending watcher */ 56 | 57 | VARx(ev_tstamp, io_blocktime) 58 | VARx(ev_tstamp, timeout_blocktime) 59 | 60 | VARx(int, backend) 61 | VARx(int, activecnt) /* total number of active events ("refcount") */ 62 | VARx(EV_ATOMIC_T, loop_done) /* signal by ev_break */ 63 | 64 | VARx(int, backend_fd) 65 | VARx(ev_tstamp, backend_mintime) /* assumed typical timer resolution */ 66 | VAR (backend_modify, void (*backend_modify)(EV_P_ int fd, int oev, int nev)) 67 | VAR (backend_poll , void (*backend_poll)(EV_P_ ev_tstamp timeout)) 68 | 69 | VARx(ANFD *, anfds) 70 | VARx(int, anfdmax) 71 | 72 | VAR (evpipe, int evpipe [2]) 73 | VARx(ev_io, pipe_w) 74 | VARx(EV_ATOMIC_T, pipe_write_wanted) 75 | VARx(EV_ATOMIC_T, pipe_write_skipped) 76 | 77 | #if !defined(_WIN32) || EV_GENWRAP 78 | VARx(pid_t, curpid) 79 | #endif 80 | 81 | VARx(char, postfork) /* true if we need to recreate kernel state after fork */ 82 | 83 | #if EV_USE_SELECT || EV_GENWRAP 84 | VARx(void *, vec_ri) 85 | VARx(void *, vec_ro) 86 | VARx(void *, vec_wi) 87 | VARx(void *, vec_wo) 88 | #if defined(_WIN32) || EV_GENWRAP 89 | VARx(void *, vec_eo) 90 | #endif 91 | VARx(int, vec_max) 92 | #endif 93 | 94 | #if EV_USE_POLL || EV_GENWRAP 95 | VARx(struct pollfd *, polls) 96 | VARx(int, pollmax) 97 | VARx(int, pollcnt) 98 | VARx(int *, pollidxs) /* maps fds into structure indices */ 99 | VARx(int, pollidxmax) 100 | #endif 101 | 102 | #if EV_USE_EPOLL || EV_GENWRAP 103 | VARx(struct epoll_event *, epoll_events) 104 | VARx(int, epoll_eventmax) 105 | VARx(int *, epoll_eperms) 106 | VARx(int, epoll_epermcnt) 107 | VARx(int, epoll_epermmax) 108 | #endif 109 | 110 | #if EV_USE_LINUXAIO || EV_GENWRAP 111 | VARx(aio_context_t, linuxaio_ctx) 112 | VARx(int, linuxaio_iteration) 113 | VARx(struct aniocb **, linuxaio_iocbps) 114 | VARx(int, linuxaio_iocbpmax) 115 | VARx(struct iocb **, linuxaio_submits) 116 | VARx(int, linuxaio_submitcnt) 117 | VARx(int, linuxaio_submitmax) 118 | VARx(ev_io, linuxaio_epoll_w) 119 | #endif 120 | 121 | #if EV_USE_IOURING || EV_GENWRAP 122 | VARx(int, iouring_fd) 123 | VARx(unsigned, iouring_to_submit); 124 | VARx(int, iouring_entries) 125 | VARx(int, iouring_max_entries) 126 | VARx(void *, iouring_sq_ring) 127 | VARx(void *, iouring_cq_ring) 128 | VARx(void *, iouring_sqes) 129 | VARx(uint32_t, iouring_sq_ring_size) 130 | VARx(uint32_t, iouring_cq_ring_size) 131 | VARx(uint32_t, iouring_sqes_size) 132 | VARx(uint32_t, iouring_sq_head) 133 | VARx(uint32_t, iouring_sq_tail) 134 | VARx(uint32_t, iouring_sq_ring_mask) 135 | VARx(uint32_t, iouring_sq_ring_entries) 136 | VARx(uint32_t, iouring_sq_flags) 137 | VARx(uint32_t, iouring_sq_dropped) 138 | VARx(uint32_t, iouring_sq_array) 139 | VARx(uint32_t, iouring_cq_head) 140 | VARx(uint32_t, iouring_cq_tail) 141 | VARx(uint32_t, iouring_cq_ring_mask) 142 | VARx(uint32_t, iouring_cq_ring_entries) 143 | VARx(uint32_t, iouring_cq_overflow) 144 | VARx(uint32_t, iouring_cq_cqes) 145 | VARx(ev_tstamp, iouring_tfd_to) 146 | VARx(int, iouring_tfd) 147 | VARx(ev_io, iouring_tfd_w) 148 | #endif 149 | 150 | #if EV_USE_KQUEUE || EV_GENWRAP 151 | VARx(pid_t, kqueue_fd_pid) 152 | VARx(struct kevent *, kqueue_changes) 153 | VARx(int, kqueue_changemax) 154 | VARx(int, kqueue_changecnt) 155 | VARx(struct kevent *, kqueue_events) 156 | VARx(int, kqueue_eventmax) 157 | #endif 158 | 159 | #if EV_USE_PORT || EV_GENWRAP 160 | VARx(struct port_event *, port_events) 161 | VARx(int, port_eventmax) 162 | #endif 163 | 164 | #if EV_USE_IOCP || EV_GENWRAP 165 | VARx(HANDLE, iocp) 166 | #endif 167 | 168 | VARx(int *, fdchanges) 169 | VARx(int, fdchangemax) 170 | VARx(int, fdchangecnt) 171 | 172 | VARx(ANHE *, timers) 173 | VARx(int, timermax) 174 | VARx(int, timercnt) 175 | 176 | #if EV_PERIODIC_ENABLE || EV_GENWRAP 177 | VARx(ANHE *, periodics) 178 | VARx(int, periodicmax) 179 | VARx(int, periodiccnt) 180 | #endif 181 | 182 | #if EV_IDLE_ENABLE || EV_GENWRAP 183 | VAR (idles, ev_idle **idles [NUMPRI]) 184 | VAR (idlemax, int idlemax [NUMPRI]) 185 | VAR (idlecnt, int idlecnt [NUMPRI]) 186 | #endif 187 | VARx(int, idleall) /* total number */ 188 | 189 | VARx(struct ev_prepare **, prepares) 190 | VARx(int, preparemax) 191 | VARx(int, preparecnt) 192 | 193 | VARx(struct ev_check **, checks) 194 | VARx(int, checkmax) 195 | VARx(int, checkcnt) 196 | 197 | #if EV_FORK_ENABLE || EV_GENWRAP 198 | VARx(struct ev_fork **, forks) 199 | VARx(int, forkmax) 200 | VARx(int, forkcnt) 201 | #endif 202 | 203 | #if EV_CLEANUP_ENABLE || EV_GENWRAP 204 | VARx(struct ev_cleanup **, cleanups) 205 | VARx(int, cleanupmax) 206 | VARx(int, cleanupcnt) 207 | #endif 208 | 209 | #if EV_ASYNC_ENABLE || EV_GENWRAP 210 | VARx(EV_ATOMIC_T, async_pending) 211 | VARx(struct ev_async **, asyncs) 212 | VARx(int, asyncmax) 213 | VARx(int, asynccnt) 214 | #endif 215 | 216 | #if EV_USE_INOTIFY || EV_GENWRAP 217 | VARx(int, fs_fd) 218 | VARx(ev_io, fs_w) 219 | VARx(char, fs_2625) /* whether we are running in linux 2.6.25 or newer */ 220 | VAR (fs_hash, ANFS fs_hash [EV_INOTIFY_HASHSIZE]) 221 | #endif 222 | 223 | VARx(EV_ATOMIC_T, sig_pending) 224 | #if EV_USE_SIGNALFD || EV_GENWRAP 225 | VARx(int, sigfd) 226 | VARx(ev_io, sigfd_w) 227 | VARx(sigset_t, sigfd_set) 228 | #endif 229 | 230 | #if EV_USE_TIMERFD || EV_GENWRAP 231 | VARx(int, timerfd) /* timerfd for time jump detection */ 232 | VARx(ev_io, timerfd_w) 233 | #endif 234 | 235 | VARx(unsigned int, origflags) /* original loop flags */ 236 | 237 | #if EV_FEATURE_API || EV_GENWRAP 238 | VARx(unsigned int, loop_count) /* total number of loop iterations/blocks */ 239 | VARx(unsigned int, loop_depth) /* #ev_run enters - #ev_run leaves */ 240 | 241 | VARx(void *, userdata) 242 | /* C++ doesn't support the ev_loop_callback typedef here. stinks. */ 243 | VAR (release_cb, void (*release_cb)(EV_P) EV_NOEXCEPT) 244 | VAR (acquire_cb, void (*acquire_cb)(EV_P) EV_NOEXCEPT) 245 | VAR (invoke_cb , ev_loop_callback invoke_cb) 246 | #endif 247 | 248 | #undef VARx 249 | 250 | -------------------------------------------------------------------------------- /libev/ev_wrap.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT, automatically generated by update_ev_wrap */ 2 | #ifndef EV_WRAP_H 3 | #define EV_WRAP_H 4 | #define acquire_cb ((loop)->acquire_cb) 5 | #define activecnt ((loop)->activecnt) 6 | #define anfdmax ((loop)->anfdmax) 7 | #define anfds ((loop)->anfds) 8 | #define async_pending ((loop)->async_pending) 9 | #define asynccnt ((loop)->asynccnt) 10 | #define asyncmax ((loop)->asyncmax) 11 | #define asyncs ((loop)->asyncs) 12 | #define backend ((loop)->backend) 13 | #define backend_fd ((loop)->backend_fd) 14 | #define backend_mintime ((loop)->backend_mintime) 15 | #define backend_modify ((loop)->backend_modify) 16 | #define backend_poll ((loop)->backend_poll) 17 | #define checkcnt ((loop)->checkcnt) 18 | #define checkmax ((loop)->checkmax) 19 | #define checks ((loop)->checks) 20 | #define cleanupcnt ((loop)->cleanupcnt) 21 | #define cleanupmax ((loop)->cleanupmax) 22 | #define cleanups ((loop)->cleanups) 23 | #define curpid ((loop)->curpid) 24 | #define epoll_epermcnt ((loop)->epoll_epermcnt) 25 | #define epoll_epermmax ((loop)->epoll_epermmax) 26 | #define epoll_eperms ((loop)->epoll_eperms) 27 | #define epoll_eventmax ((loop)->epoll_eventmax) 28 | #define epoll_events ((loop)->epoll_events) 29 | #define evpipe ((loop)->evpipe) 30 | #define fdchangecnt ((loop)->fdchangecnt) 31 | #define fdchangemax ((loop)->fdchangemax) 32 | #define fdchanges ((loop)->fdchanges) 33 | #define forkcnt ((loop)->forkcnt) 34 | #define forkmax ((loop)->forkmax) 35 | #define forks ((loop)->forks) 36 | #define fs_2625 ((loop)->fs_2625) 37 | #define fs_fd ((loop)->fs_fd) 38 | #define fs_hash ((loop)->fs_hash) 39 | #define fs_w ((loop)->fs_w) 40 | #define idleall ((loop)->idleall) 41 | #define idlecnt ((loop)->idlecnt) 42 | #define idlemax ((loop)->idlemax) 43 | #define idles ((loop)->idles) 44 | #define invoke_cb ((loop)->invoke_cb) 45 | #define io_blocktime ((loop)->io_blocktime) 46 | #define iocp ((loop)->iocp) 47 | #define iouring_cq_cqes ((loop)->iouring_cq_cqes) 48 | #define iouring_cq_head ((loop)->iouring_cq_head) 49 | #define iouring_cq_overflow ((loop)->iouring_cq_overflow) 50 | #define iouring_cq_ring ((loop)->iouring_cq_ring) 51 | #define iouring_cq_ring_entries ((loop)->iouring_cq_ring_entries) 52 | #define iouring_cq_ring_mask ((loop)->iouring_cq_ring_mask) 53 | #define iouring_cq_ring_size ((loop)->iouring_cq_ring_size) 54 | #define iouring_cq_tail ((loop)->iouring_cq_tail) 55 | #define iouring_entries ((loop)->iouring_entries) 56 | #define iouring_fd ((loop)->iouring_fd) 57 | #define iouring_max_entries ((loop)->iouring_max_entries) 58 | #define iouring_sq_array ((loop)->iouring_sq_array) 59 | #define iouring_sq_dropped ((loop)->iouring_sq_dropped) 60 | #define iouring_sq_flags ((loop)->iouring_sq_flags) 61 | #define iouring_sq_head ((loop)->iouring_sq_head) 62 | #define iouring_sq_ring ((loop)->iouring_sq_ring) 63 | #define iouring_sq_ring_entries ((loop)->iouring_sq_ring_entries) 64 | #define iouring_sq_ring_mask ((loop)->iouring_sq_ring_mask) 65 | #define iouring_sq_ring_size ((loop)->iouring_sq_ring_size) 66 | #define iouring_sq_tail ((loop)->iouring_sq_tail) 67 | #define iouring_sqes ((loop)->iouring_sqes) 68 | #define iouring_sqes_size ((loop)->iouring_sqes_size) 69 | #define iouring_tfd ((loop)->iouring_tfd) 70 | #define iouring_tfd_to ((loop)->iouring_tfd_to) 71 | #define iouring_tfd_w ((loop)->iouring_tfd_w) 72 | #define iouring_to_submit ((loop)->iouring_to_submit) 73 | #define kqueue_changecnt ((loop)->kqueue_changecnt) 74 | #define kqueue_changemax ((loop)->kqueue_changemax) 75 | #define kqueue_changes ((loop)->kqueue_changes) 76 | #define kqueue_eventmax ((loop)->kqueue_eventmax) 77 | #define kqueue_events ((loop)->kqueue_events) 78 | #define kqueue_fd_pid ((loop)->kqueue_fd_pid) 79 | #define linuxaio_ctx ((loop)->linuxaio_ctx) 80 | #define linuxaio_epoll_w ((loop)->linuxaio_epoll_w) 81 | #define linuxaio_iocbpmax ((loop)->linuxaio_iocbpmax) 82 | #define linuxaio_iocbps ((loop)->linuxaio_iocbps) 83 | #define linuxaio_iteration ((loop)->linuxaio_iteration) 84 | #define linuxaio_submitcnt ((loop)->linuxaio_submitcnt) 85 | #define linuxaio_submitmax ((loop)->linuxaio_submitmax) 86 | #define linuxaio_submits ((loop)->linuxaio_submits) 87 | #define loop_count ((loop)->loop_count) 88 | #define loop_depth ((loop)->loop_depth) 89 | #define loop_done ((loop)->loop_done) 90 | #define mn_now ((loop)->mn_now) 91 | #define now_floor ((loop)->now_floor) 92 | #define origflags ((loop)->origflags) 93 | #define pending_w ((loop)->pending_w) 94 | #define pendingcnt ((loop)->pendingcnt) 95 | #define pendingmax ((loop)->pendingmax) 96 | #define pendingpri ((loop)->pendingpri) 97 | #define pendings ((loop)->pendings) 98 | #define periodiccnt ((loop)->periodiccnt) 99 | #define periodicmax ((loop)->periodicmax) 100 | #define periodics ((loop)->periodics) 101 | #define pipe_w ((loop)->pipe_w) 102 | #define pipe_write_skipped ((loop)->pipe_write_skipped) 103 | #define pipe_write_wanted ((loop)->pipe_write_wanted) 104 | #define pollcnt ((loop)->pollcnt) 105 | #define pollidxmax ((loop)->pollidxmax) 106 | #define pollidxs ((loop)->pollidxs) 107 | #define pollmax ((loop)->pollmax) 108 | #define polls ((loop)->polls) 109 | #define port_eventmax ((loop)->port_eventmax) 110 | #define port_events ((loop)->port_events) 111 | #define postfork ((loop)->postfork) 112 | #define preparecnt ((loop)->preparecnt) 113 | #define preparemax ((loop)->preparemax) 114 | #define prepares ((loop)->prepares) 115 | #define release_cb ((loop)->release_cb) 116 | #define rfeedcnt ((loop)->rfeedcnt) 117 | #define rfeedmax ((loop)->rfeedmax) 118 | #define rfeeds ((loop)->rfeeds) 119 | #define rtmn_diff ((loop)->rtmn_diff) 120 | #define sig_pending ((loop)->sig_pending) 121 | #define sigfd ((loop)->sigfd) 122 | #define sigfd_set ((loop)->sigfd_set) 123 | #define sigfd_w ((loop)->sigfd_w) 124 | #define timeout_blocktime ((loop)->timeout_blocktime) 125 | #define timercnt ((loop)->timercnt) 126 | #define timerfd ((loop)->timerfd) 127 | #define timerfd_w ((loop)->timerfd_w) 128 | #define timermax ((loop)->timermax) 129 | #define timers ((loop)->timers) 130 | #define userdata ((loop)->userdata) 131 | #define vec_eo ((loop)->vec_eo) 132 | #define vec_max ((loop)->vec_max) 133 | #define vec_ri ((loop)->vec_ri) 134 | #define vec_ro ((loop)->vec_ro) 135 | #define vec_wi ((loop)->vec_wi) 136 | #define vec_wo ((loop)->vec_wo) 137 | #else 138 | #undef EV_WRAP_H 139 | #undef acquire_cb 140 | #undef activecnt 141 | #undef anfdmax 142 | #undef anfds 143 | #undef async_pending 144 | #undef asynccnt 145 | #undef asyncmax 146 | #undef asyncs 147 | #undef backend 148 | #undef backend_fd 149 | #undef backend_mintime 150 | #undef backend_modify 151 | #undef backend_poll 152 | #undef checkcnt 153 | #undef checkmax 154 | #undef checks 155 | #undef cleanupcnt 156 | #undef cleanupmax 157 | #undef cleanups 158 | #undef curpid 159 | #undef epoll_epermcnt 160 | #undef epoll_epermmax 161 | #undef epoll_eperms 162 | #undef epoll_eventmax 163 | #undef epoll_events 164 | #undef evpipe 165 | #undef fdchangecnt 166 | #undef fdchangemax 167 | #undef fdchanges 168 | #undef forkcnt 169 | #undef forkmax 170 | #undef forks 171 | #undef fs_2625 172 | #undef fs_fd 173 | #undef fs_hash 174 | #undef fs_w 175 | #undef idleall 176 | #undef idlecnt 177 | #undef idlemax 178 | #undef idles 179 | #undef invoke_cb 180 | #undef io_blocktime 181 | #undef iocp 182 | #undef iouring_cq_cqes 183 | #undef iouring_cq_head 184 | #undef iouring_cq_overflow 185 | #undef iouring_cq_ring 186 | #undef iouring_cq_ring_entries 187 | #undef iouring_cq_ring_mask 188 | #undef iouring_cq_ring_size 189 | #undef iouring_cq_tail 190 | #undef iouring_entries 191 | #undef iouring_fd 192 | #undef iouring_max_entries 193 | #undef iouring_sq_array 194 | #undef iouring_sq_dropped 195 | #undef iouring_sq_flags 196 | #undef iouring_sq_head 197 | #undef iouring_sq_ring 198 | #undef iouring_sq_ring_entries 199 | #undef iouring_sq_ring_mask 200 | #undef iouring_sq_ring_size 201 | #undef iouring_sq_tail 202 | #undef iouring_sqes 203 | #undef iouring_sqes_size 204 | #undef iouring_tfd 205 | #undef iouring_tfd_to 206 | #undef iouring_tfd_w 207 | #undef iouring_to_submit 208 | #undef kqueue_changecnt 209 | #undef kqueue_changemax 210 | #undef kqueue_changes 211 | #undef kqueue_eventmax 212 | #undef kqueue_events 213 | #undef kqueue_fd_pid 214 | #undef linuxaio_ctx 215 | #undef linuxaio_epoll_w 216 | #undef linuxaio_iocbpmax 217 | #undef linuxaio_iocbps 218 | #undef linuxaio_iteration 219 | #undef linuxaio_submitcnt 220 | #undef linuxaio_submitmax 221 | #undef linuxaio_submits 222 | #undef loop_count 223 | #undef loop_depth 224 | #undef loop_done 225 | #undef mn_now 226 | #undef now_floor 227 | #undef origflags 228 | #undef pending_w 229 | #undef pendingcnt 230 | #undef pendingmax 231 | #undef pendingpri 232 | #undef pendings 233 | #undef periodiccnt 234 | #undef periodicmax 235 | #undef periodics 236 | #undef pipe_w 237 | #undef pipe_write_skipped 238 | #undef pipe_write_wanted 239 | #undef pollcnt 240 | #undef pollidxmax 241 | #undef pollidxs 242 | #undef pollmax 243 | #undef polls 244 | #undef port_eventmax 245 | #undef port_events 246 | #undef postfork 247 | #undef preparecnt 248 | #undef preparemax 249 | #undef prepares 250 | #undef release_cb 251 | #undef rfeedcnt 252 | #undef rfeedmax 253 | #undef rfeeds 254 | #undef rtmn_diff 255 | #undef sig_pending 256 | #undef sigfd 257 | #undef sigfd_set 258 | #undef sigfd_w 259 | #undef timeout_blocktime 260 | #undef timercnt 261 | #undef timerfd 262 | #undef timerfd_w 263 | #undef timermax 264 | #undef timers 265 | #undef userdata 266 | #undef vec_eo 267 | #undef vec_max 268 | #undef vec_ri 269 | #undef vec_ro 270 | #undef vec_wi 271 | #undef vec_wo 272 | #endif 273 | -------------------------------------------------------------------------------- /src/ipt2socks.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include "logutils.h" 3 | #include "lrucache.h" 4 | #include "netutils.h" 5 | #include "protocol.h" 6 | #include "../libev/ev.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | /* splice() api */ 25 | #ifndef SPLICE_F_MOVE 26 | #include 27 | 28 | #undef SPLICE_F_MOVE 29 | #define SPLICE_F_MOVE 1 30 | 31 | #undef SPLICE_F_NONBLOCK 32 | #define SPLICE_F_NONBLOCK 2 33 | 34 | #define splice(fdin, offin, fdout, offout, len, flags) syscall(__NR_splice, fdin, offin, fdout, offout, len, flags) 35 | #endif 36 | 37 | #define IF_VERBOSE if (g_verbose) 38 | 39 | #define TCP_SPLICE_MAXLEN 65535 /* uint16_t: 0~65535 */ 40 | 41 | #define IPT2SOCKS_VERSION "ipt2socks v1.1.5 " 42 | 43 | enum { 44 | OPT_ENABLE_TCP = 0x01 << 0, // enable tcp proxy 45 | OPT_ENABLE_UDP = 0x01 << 1, // enable udp proxy 46 | OPT_ENABLE_IPV4 = 0x01 << 2, // enable ipv4 proxy 47 | OPT_ENABLE_IPV6 = 0x01 << 3, // enable ipv6 proxy 48 | OPT_TCP_USE_REDIRECT = 0x01 << 4, // use redirect instead of tproxy (used by tcp) 49 | OPT_ALWAYS_REUSE_PORT = 0x01 << 5, // always enable so_reuseport (since linux 3.9+) 50 | OPT_ENABLE_TFO_ACCEPT = 0x01 << 6, // enable tcp_fastopen for listen socket (server tfo) 51 | OPT_ENABLE_TFO_CONNECT = 0x01 << 7, // enable tcp_fastopen for connect socket (client tfo) 52 | }; 53 | 54 | typedef struct { 55 | evio_t client_watcher; // .data: socks5 mesg 56 | evio_t socks5_watcher; // .data: socks5 mesg 57 | int client_pipefd[2]; // client pipe buffer 58 | int socks5_pipefd[2]; // socks5 pipe buffer 59 | uint16_t client_length; // nrecv/nsend, npipe 60 | uint16_t socks5_length; // nrecv/nsend, npipe 61 | } tcp_context_t; 62 | 63 | static void* run_event_loop(void *is_main_thread); 64 | 65 | static void tcp_tproxy_accept_cb(evloop_t *evloop, evio_t *watcher, int revents); 66 | static void tcp_socks5_connect_cb(evloop_t *evloop, evio_t *watcher, int revents); 67 | static void tcp_socks5_send_authreq_cb(evloop_t *evloop, evio_t *watcher, int revents); 68 | static void tcp_socks5_recv_authresp_cb(evloop_t *evloop, evio_t *watcher, int revents); 69 | static void tcp_socks5_send_usrpwdreq_cb(evloop_t *evloop, evio_t *watcher, int revents); 70 | static void tcp_socks5_recv_usrpwdresp_cb(evloop_t *evloop, evio_t *watcher, int revents); 71 | static void tcp_socks5_send_proxyreq_cb(evloop_t *evloop, evio_t *watcher, int revents); 72 | static void tcp_socks5_recv_proxyresp_cb(evloop_t *evloop, evio_t *watcher, int revents); 73 | static void tcp_stream_payload_forward_cb(evloop_t *evloop, evio_t *watcher, int revents); 74 | 75 | static void udp_tproxy_recvmsg_cb(evloop_t *evloop, evio_t *watcher, int revents); 76 | static void udp_socks5_connect_cb(evloop_t *evloop, evio_t *watcher, int revents); 77 | static void udp_socks5_send_authreq_cb(evloop_t *evloop, evio_t *watcher, int revents); 78 | static void udp_socks5_recv_authresp_cb(evloop_t *evloop, evio_t *watcher, int revents); 79 | static void udp_socks5_send_usrpwdreq_cb(evloop_t *evloop, evio_t *watcher, int revents); 80 | static void udp_socks5_recv_usrpwdresp_cb(evloop_t *evloop, evio_t *watcher, int revents); 81 | static void udp_socks5_send_proxyreq_cb(evloop_t *evloop, evio_t *watcher, int revents); 82 | static void udp_socks5_recv_proxyresp_cb(evloop_t *evloop, evio_t *watcher, int revents); 83 | static void udp_socks5_recv_tcpmessage_cb(evloop_t *evloop, evio_t *watcher, int revents); 84 | static void udp_socks5_recv_udpmessage_cb(evloop_t *evloop, evio_t *watcher, int revents); 85 | static void udp_socks5_context_timeout_cb(evloop_t *evloop, evtimer_t *watcher, int revents); 86 | static void udp_tproxy_context_timeout_cb(evloop_t *evloop, evtimer_t *watcher, int revents); 87 | 88 | static bool g_verbose = false; 89 | static uint16_t g_options = OPT_ENABLE_TCP | OPT_ENABLE_UDP | OPT_ENABLE_IPV4 | OPT_ENABLE_IPV6; 90 | static uint8_t g_nthreads = 1; 91 | 92 | static char g_bind_ipstr4[IP4STRLEN] = IP4STR_LOOPBACK; 93 | static char g_bind_ipstr6[IP6STRLEN] = IP6STR_LOOPBACK; 94 | static portno_t g_bind_portno = 60080; 95 | static skaddr4_t g_bind_skaddr4 = {0}; 96 | static skaddr6_t g_bind_skaddr6 = {0}; 97 | 98 | static char g_server_ipstr[IP6STRLEN] = "127.0.0.1"; 99 | static portno_t g_server_portno = 1080; 100 | static skaddr6_t g_server_skaddr = {0}; 101 | 102 | static uint8_t g_tcp_syncnt_max = 0; // 0: use default syncnt 103 | 104 | static uint16_t g_udp_idletimeout_sec = 60; 105 | static udp_socks5ctx_t *g_udp_socks5ctx_table = NULL; 106 | static udp_tproxyctx_t *g_udp_tproxyctx_table = NULL; 107 | static char g_udp_dgram_buffer[UDP_DATAGRAM_MAXSIZ] = {0}; 108 | 109 | static void print_command_help(void) { 110 | printf("usage: ipt2socks . the existing options are as follows:\n" 111 | " -s, --server-addr socks5 server ip, default: 127.0.0.1\n" 112 | " -p, --server-port socks5 server port, default: 1080\n" 113 | " -a, --auth-username username for socks5 authentication\n" 114 | " -k, --auth-password password for socks5 authentication\n" 115 | " -b, --listen-addr4 listen ipv4 address, default: 127.0.0.1\n" 116 | " -B, --listen-addr6 listen ipv6 address, default: ::1\n" 117 | " -l, --listen-port listen port number, default: 60080\n" 118 | " -S, --tcp-syncnt change the number of tcp syn retransmits\n" 119 | " -c, --cache-size udp context cache maxsize, default: 256\n" 120 | " -o, --udp-timeout udp context idle timeout, default: 60\n" 121 | " -j, --thread-nums number of the worker threads, default: 1\n" 122 | " -n, --nofile-limit set nofile limit, may need root privilege\n" 123 | " -u, --run-user run as the given user, need root privilege\n" 124 | " -T, --tcp-only listen tcp only, aka: disable udp proxy\n" 125 | " -U, --udp-only listen udp only, aka: disable tcp proxy\n" 126 | " -4, --ipv4-only listen ipv4 only, aka: disable ipv6 proxy\n" 127 | " -6, --ipv6-only listen ipv6 only, aka: disable ipv4 proxy\n" 128 | " -R, --redirect use redirect instead of tproxy for tcp\n" 129 | " -r, --reuse-port enable so_reuseport for single thread\n" 130 | " -w, --tfo-accept enable tcp_fastopen for server socket\n" 131 | " -W, --tfo-connect enable tcp_fastopen for client socket\n" 132 | " -v, --verbose print verbose log, affect performance\n" 133 | " -V, --version print ipt2socks version number and exit\n" 134 | " -h, --help print ipt2socks help information and exit\n" 135 | ); 136 | } 137 | 138 | static void parse_command_args(int argc, char* argv[]) { 139 | opterr = 0; /* disable errmsg print, can get error by retval '?' */ 140 | const char *optstr = ":s:p:a:k:b:B:l:S:c:o:j:n:u:TU46RrwWvVh"; 141 | const struct option options[] = { 142 | {"server-addr", required_argument, NULL, 's'}, 143 | {"server-port", required_argument, NULL, 'p'}, 144 | {"auth-username", required_argument, NULL, 'a'}, 145 | {"auth-password", required_argument, NULL, 'k'}, 146 | {"listen-addr4", required_argument, NULL, 'b'}, 147 | {"listen-addr6", required_argument, NULL, 'B'}, 148 | {"listen-port", required_argument, NULL, 'l'}, 149 | {"tcp-syncnt", required_argument, NULL, 'S'}, 150 | {"cache-size", required_argument, NULL, 'c'}, 151 | {"udp-timeout", required_argument, NULL, 'o'}, 152 | {"thread-nums", required_argument, NULL, 'j'}, 153 | {"nofile-limit", required_argument, NULL, 'n'}, 154 | {"run-user", required_argument, NULL, 'u'}, 155 | {"tcp-only", no_argument, NULL, 'T'}, 156 | {"udp-only", no_argument, NULL, 'U'}, 157 | {"ipv4-only", no_argument, NULL, '4'}, 158 | {"ipv6-only", no_argument, NULL, '6'}, 159 | {"redirect", no_argument, NULL, 'R'}, 160 | {"reuse-port", no_argument, NULL, 'r'}, 161 | {"tfo-accept", no_argument, NULL, 'w'}, 162 | {"tfo-connect", no_argument, NULL, 'W'}, 163 | {"verbose", no_argument, NULL, 'v'}, 164 | {"version", no_argument, NULL, 'V'}, 165 | {"help", no_argument, NULL, 'h'}, 166 | {NULL, 0, NULL, 0}, 167 | }; 168 | 169 | const char *optval_auth_username = NULL; 170 | const char *optval_auth_password = NULL; 171 | 172 | int shortopt = -1; 173 | while ((shortopt = getopt_long(argc, argv, optstr, options, NULL)) != -1) { 174 | switch (shortopt) { 175 | case 's': 176 | if (strlen(optarg) + 1 > IP6STRLEN) { 177 | printf("[parse_command_args] ip address max length is 45: %s\n", optarg); 178 | goto PRINT_HELP_AND_EXIT; 179 | } 180 | if (get_ipstr_family(optarg) == -1) { 181 | printf("[parse_command_args] invalid server ip address: %s\n", optarg); 182 | goto PRINT_HELP_AND_EXIT; 183 | } 184 | strcpy(g_server_ipstr, optarg); 185 | break; 186 | case 'p': 187 | if (strlen(optarg) + 1 > PORTSTRLEN) { 188 | printf("[parse_command_args] port number max length is 5: %s\n", optarg); 189 | goto PRINT_HELP_AND_EXIT; 190 | } 191 | g_server_portno = strtoul(optarg, NULL, 10); 192 | if (g_server_portno == 0) { 193 | printf("[parse_command_args] invalid server port number: %s\n", optarg); 194 | goto PRINT_HELP_AND_EXIT; 195 | } 196 | break; 197 | case 'a': 198 | if (strlen(optarg) > SOCKS5_USRPWD_USRMAXLEN) { 199 | printf("[parse_command_args] socks5 username max length is 255: %s\n", optarg); 200 | goto PRINT_HELP_AND_EXIT; 201 | } 202 | optval_auth_username = optarg; 203 | break; 204 | case 'k': 205 | if (strlen(optarg) > SOCKS5_USRPWD_PWDMAXLEN) { 206 | printf("[parse_command_args] socks5 password max length is 255: %s\n", optarg); 207 | goto PRINT_HELP_AND_EXIT; 208 | } 209 | optval_auth_password = optarg; 210 | break; 211 | case 'b': 212 | if (strlen(optarg) + 1 > IP4STRLEN) { 213 | printf("[parse_command_args] ipv4 address max length is 15: %s\n", optarg); 214 | goto PRINT_HELP_AND_EXIT; 215 | } 216 | if (get_ipstr_family(optarg) != AF_INET) { 217 | printf("[parse_command_args] invalid listen ipv4 address: %s\n", optarg); 218 | goto PRINT_HELP_AND_EXIT; 219 | } 220 | strcpy(g_bind_ipstr4, optarg); 221 | break; 222 | case 'B': 223 | if (strlen(optarg) + 1 > IP6STRLEN) { 224 | printf("[parse_command_args] ipv6 address max length is 45: %s\n", optarg); 225 | goto PRINT_HELP_AND_EXIT; 226 | } 227 | if (get_ipstr_family(optarg) != AF_INET6) { 228 | printf("[parse_command_args] invalid listen ipv6 address: %s\n", optarg); 229 | goto PRINT_HELP_AND_EXIT; 230 | } 231 | strcpy(g_bind_ipstr6, optarg); 232 | break; 233 | case 'l': 234 | if (strlen(optarg) + 1 > PORTSTRLEN) { 235 | printf("[parse_command_args] port number max length is 5: %s\n", optarg); 236 | goto PRINT_HELP_AND_EXIT; 237 | } 238 | g_bind_portno = strtoul(optarg, NULL, 10); 239 | if (g_bind_portno == 0) { 240 | printf("[parse_command_args] invalid listen port number: %s\n", optarg); 241 | goto PRINT_HELP_AND_EXIT; 242 | } 243 | break; 244 | case 'S': 245 | g_tcp_syncnt_max = strtoul(optarg, NULL, 10); 246 | if (g_tcp_syncnt_max == 0) { 247 | printf("[parse_command_args] invalid number of syn retransmits: %s\n", optarg); 248 | goto PRINT_HELP_AND_EXIT; 249 | } 250 | break; 251 | case 'c': 252 | if (strtoul(optarg, NULL, 10) == 0) { 253 | printf("[parse_command_args] invalid maxsize of udp lrucache: %s\n", optarg); 254 | goto PRINT_HELP_AND_EXIT; 255 | } 256 | lrucache_set_maxsize(strtoul(optarg, NULL, 10)); 257 | break; 258 | case 'o': 259 | g_udp_idletimeout_sec = strtoul(optarg, NULL, 10); 260 | if (g_udp_idletimeout_sec == 0) { 261 | printf("[parse_command_args] invalid udp socket idle timeout: %s\n", optarg); 262 | goto PRINT_HELP_AND_EXIT; 263 | } 264 | break; 265 | case 'j': 266 | g_nthreads = strtoul(optarg, NULL, 10); 267 | if (g_nthreads == 0) { 268 | printf("[parse_command_args] invalid number of worker threads: %s\n", optarg); 269 | goto PRINT_HELP_AND_EXIT; 270 | } 271 | break; 272 | case 'n': 273 | set_nofile_limit(strtoul(optarg, NULL, 10)); 274 | break; 275 | case 'u': 276 | run_as_user(optarg, argv); 277 | break; 278 | case 'T': 279 | g_options &= ~OPT_ENABLE_UDP; 280 | break; 281 | case 'U': 282 | g_options &= ~OPT_ENABLE_TCP; 283 | break; 284 | case '4': 285 | g_options &= ~OPT_ENABLE_IPV6; 286 | break; 287 | case '6': 288 | g_options &= ~OPT_ENABLE_IPV4; 289 | break; 290 | case 'R': 291 | g_options |= OPT_TCP_USE_REDIRECT; 292 | strcpy(g_bind_ipstr4, IP4STR_WILDCARD); 293 | strcpy(g_bind_ipstr6, IP6STR_WILDCARD); 294 | break; 295 | case 'r': 296 | g_options |= OPT_ALWAYS_REUSE_PORT; 297 | break; 298 | case 'w': 299 | g_options |= OPT_ENABLE_TFO_ACCEPT; 300 | break; 301 | case 'W': 302 | g_options |= OPT_ENABLE_TFO_CONNECT; 303 | break; 304 | case 'v': 305 | g_verbose = true; 306 | break; 307 | case 'V': 308 | printf(IPT2SOCKS_VERSION"\n"); 309 | exit(0); 310 | case 'h': 311 | print_command_help(); 312 | exit(0); 313 | case ':': 314 | printf("[parse_command_args] missing optarg: '%s'\n", argv[optind - 1]); 315 | goto PRINT_HELP_AND_EXIT; 316 | case '?': 317 | if (optopt) { 318 | printf("[parse_command_args] unknown option: '-%c'\n", optopt); 319 | } else { 320 | char *longopt = argv[optind - 1]; 321 | char *equalsign = strchr(longopt, '='); 322 | if (equalsign) *equalsign = 0; 323 | printf("[parse_command_args] unknown option: '%s'\n", longopt); 324 | } 325 | goto PRINT_HELP_AND_EXIT; 326 | } 327 | } 328 | 329 | if (!(g_options & (OPT_ENABLE_TCP | OPT_ENABLE_UDP))) { 330 | printf("[parse_command_args] both tcp and udp are disabled, nothing to do\n"); 331 | goto PRINT_HELP_AND_EXIT; 332 | } 333 | if (!(g_options & (OPT_ENABLE_IPV4 | OPT_ENABLE_IPV6))) { 334 | printf("[parse_command_args] both ipv4 and ipv6 are disabled, nothing to do\n"); 335 | goto PRINT_HELP_AND_EXIT; 336 | } 337 | 338 | if (optval_auth_username && !optval_auth_password) { 339 | printf("[parse_command_args] username specified, but password is not provided\n"); 340 | goto PRINT_HELP_AND_EXIT; 341 | } 342 | if (!optval_auth_username && optval_auth_password) { 343 | printf("[parse_command_args] password specified, but username is not provided\n"); 344 | goto PRINT_HELP_AND_EXIT; 345 | } 346 | if (optval_auth_username && optval_auth_password) { 347 | socks5_usrpwd_request_make(optval_auth_username, optval_auth_password); 348 | } 349 | 350 | if (!(g_options & OPT_ENABLE_TCP)) g_nthreads = 1; 351 | 352 | build_socket_addr(AF_INET, &g_bind_skaddr4, g_bind_ipstr4, g_bind_portno); 353 | build_socket_addr(AF_INET6, &g_bind_skaddr6, g_bind_ipstr6, g_bind_portno); 354 | build_socket_addr(get_ipstr_family(g_server_ipstr), &g_server_skaddr, g_server_ipstr, g_server_portno); 355 | return; 356 | 357 | PRINT_HELP_AND_EXIT: 358 | print_command_help(); 359 | exit(1); 360 | } 361 | 362 | int main(int argc, char* argv[]) { 363 | signal(SIGPIPE, SIG_IGN); 364 | setvbuf(stdout, NULL, _IOLBF, 256); 365 | parse_command_args(argc, argv); 366 | 367 | LOGINF("[main] server address: %s#%hu", g_server_ipstr, g_server_portno); 368 | if (g_options & OPT_ENABLE_IPV4) LOGINF("[main] listen address: %s#%hu", g_bind_ipstr4, g_bind_portno); 369 | if (g_options & OPT_ENABLE_IPV6) LOGINF("[main] listen address: %s#%hu", g_bind_ipstr6, g_bind_portno); 370 | if (g_tcp_syncnt_max) LOGINF("[main] max number of syn retries: %hhu", g_tcp_syncnt_max); 371 | LOGINF("[main] udp session cache capacity: %hu", lrucache_get_maxsize()); 372 | LOGINF("[main] udp session idle timeout: %hu", g_udp_idletimeout_sec); 373 | LOGINF("[main] number of worker threads: %hhu", g_nthreads); 374 | LOGINF("[main] max file descriptor limit: %zu", get_nofile_limit()); 375 | if (g_options & OPT_ENABLE_TCP) LOGINF("[main] enable tcp transparent proxy"); 376 | if (g_options & OPT_ENABLE_UDP) LOGINF("[main] enable udp transparent proxy"); 377 | if (g_options & OPT_TCP_USE_REDIRECT) LOGINF("[main] use redirect instead of tproxy"); 378 | if (g_options & OPT_ALWAYS_REUSE_PORT) LOGINF("[main] always enable reuseport feature"); 379 | if (g_options & OPT_ENABLE_TFO_ACCEPT) LOGINF("[main] enable tfo for tcp server socket"); 380 | if (g_options & OPT_ENABLE_TFO_CONNECT) LOGINF("[main] enable tfo for tcp client socket"); 381 | IF_VERBOSE LOGINF("[main] verbose mode (affect performance)"); 382 | 383 | for (int i = 0; i < g_nthreads - 1; ++i) { 384 | if (pthread_create(&(pthread_t){0}, NULL, run_event_loop, NULL)) { 385 | LOGERR("[main] create worker thread: %s", strerror(errno)); 386 | return errno; 387 | } 388 | } 389 | run_event_loop((void *)1); 390 | 391 | return 0; 392 | } 393 | 394 | static void* run_event_loop(void *is_main_thread) { 395 | evloop_t *evloop = ev_loop_new(0); 396 | 397 | if (g_options & OPT_ENABLE_TCP) { 398 | bool is_tproxy = !(g_options & OPT_TCP_USE_REDIRECT); 399 | bool is_tfo_accept = g_options & OPT_ENABLE_TFO_ACCEPT; 400 | bool is_reuse_port = g_nthreads > 1 || (g_options & OPT_ALWAYS_REUSE_PORT); 401 | 402 | if (g_options & OPT_ENABLE_IPV4) { 403 | int sockfd = new_tcp_listen_sockfd(AF_INET, is_tproxy, is_reuse_port, is_tfo_accept); 404 | 405 | if (bind(sockfd, (void *)&g_bind_skaddr4, sizeof(skaddr4_t)) < 0) { 406 | LOGERR("[run_event_loop] bind tcp4 address: %s", strerror(errno)); 407 | exit(errno); 408 | } 409 | if (listen(sockfd, SOMAXCONN) < 0) { 410 | LOGERR("[run_event_loop] listen tcp4 socket: %s", strerror(errno)); 411 | exit(errno); 412 | } 413 | 414 | evio_t *watcher = malloc(sizeof(*watcher)); 415 | watcher->data = (void *)1; /* indicates it is ipv4 */ 416 | ev_io_init(watcher, tcp_tproxy_accept_cb, sockfd, EV_READ); 417 | ev_io_start(evloop, watcher); 418 | } 419 | 420 | if (g_options & OPT_ENABLE_IPV6) { 421 | int sockfd = new_tcp_listen_sockfd(AF_INET6, is_tproxy, is_reuse_port, is_tfo_accept); 422 | 423 | if (bind(sockfd, (void *)&g_bind_skaddr6, sizeof(skaddr6_t)) < 0) { 424 | LOGERR("[run_event_loop] bind tcp6 address: %s", strerror(errno)); 425 | exit(errno); 426 | } 427 | if (listen(sockfd, SOMAXCONN) < 0) { 428 | LOGERR("[run_event_loop] listen tcp6 socket: %s", strerror(errno)); 429 | exit(errno); 430 | } 431 | 432 | evio_t *watcher = malloc(sizeof(*watcher)); 433 | watcher->data = NULL; /* indicates it not ipv4 */ 434 | ev_io_init(watcher, tcp_tproxy_accept_cb, sockfd, EV_READ); 435 | ev_io_start(evloop, watcher); 436 | } 437 | } 438 | 439 | if ((g_options & OPT_ENABLE_UDP) && is_main_thread) { 440 | if (g_options & OPT_ENABLE_IPV4) { 441 | int sockfd = new_udp_tprecv_sockfd(AF_INET); 442 | 443 | if (bind(sockfd, (void *)&g_bind_skaddr4, sizeof(skaddr4_t)) < 0) { 444 | LOGERR("[run_event_loop] bind udp4 address: %s", strerror(errno)); 445 | exit(errno); 446 | } 447 | 448 | evio_t *watcher = malloc(sizeof(*watcher)); 449 | watcher->data = (void *)1; /* indicates it is ipv4 */ 450 | ev_io_init(watcher, udp_tproxy_recvmsg_cb, sockfd, EV_READ); 451 | ev_io_start(evloop, watcher); 452 | } 453 | 454 | if (g_options & OPT_ENABLE_IPV6) { 455 | int sockfd = new_udp_tprecv_sockfd(AF_INET6); 456 | 457 | if (bind(sockfd, (void *)&g_bind_skaddr6, sizeof(skaddr6_t)) < 0) { 458 | LOGERR("[run_event_loop] bind udp6 address: %s", strerror(errno)); 459 | exit(errno); 460 | } 461 | 462 | evio_t *watcher = malloc(sizeof(*watcher)); 463 | watcher->data = NULL; /* indicates it not ipv4 */ 464 | ev_io_init(watcher, udp_tproxy_recvmsg_cb, sockfd, EV_READ); 465 | ev_io_start(evloop, watcher); 466 | } 467 | } 468 | 469 | ev_run(evloop, 0); 470 | return NULL; 471 | } 472 | 473 | static void tcp_tproxy_accept_cb(evloop_t *evloop, evio_t *accept_watcher, int revents __attribute__((unused))) { 474 | bool isipv4 = accept_watcher->data; 475 | skaddr6_t skaddr; char ipstr[IP6STRLEN]; portno_t portno; 476 | 477 | int client_sockfd = tcp_accept(accept_watcher->fd, (void *)&skaddr, &(socklen_t){sizeof(skaddr)}); 478 | if (client_sockfd < 0) { 479 | if (errno != EAGAIN && errno != EWOULDBLOCK) { 480 | LOGERR("[tcp_tproxy_accept_cb] accept tcp%s socket: %s", isipv4 ? "4" : "6", strerror(errno)); 481 | } 482 | return; 483 | } 484 | IF_VERBOSE { 485 | parse_socket_addr(&skaddr, ipstr, &portno); 486 | LOGINF("[tcp_tproxy_accept_cb] source socket address: %s#%hu", ipstr, portno); 487 | } 488 | 489 | if (!get_tcp_orig_dstaddr(isipv4 ? AF_INET : AF_INET6, client_sockfd, &skaddr, !(g_options & OPT_TCP_USE_REDIRECT))) { 490 | tcp_close_by_rst(client_sockfd); 491 | return; 492 | } 493 | IF_VERBOSE { 494 | parse_socket_addr(&skaddr, ipstr, &portno); 495 | LOGINF("[tcp_tproxy_accept_cb] target socket address: %s#%hu", ipstr, portno); 496 | } 497 | 498 | int socks5_sockfd = new_tcp_connect_sockfd(g_server_skaddr.sin6_family, g_tcp_syncnt_max); 499 | const void *tfo_data = (g_options & OPT_ENABLE_TFO_CONNECT) ? &g_socks5_auth_request : NULL; 500 | uint16_t tfo_datalen = (g_options & OPT_ENABLE_TFO_CONNECT) ? sizeof(socks5_authreq_t) : 0; 501 | ssize_t tfo_nsend = -1; /* if tfo connect succeed: tfo_nsend >= 0 */ 502 | 503 | if (!tcp_connect(socks5_sockfd, &g_server_skaddr, tfo_data, tfo_datalen, &tfo_nsend)) { 504 | LOGERR("[tcp_tproxy_accept_cb] connect to %s#%hu: %s", g_server_ipstr, g_server_portno, strerror(errno)); 505 | tcp_close_by_rst(client_sockfd); 506 | close(socks5_sockfd); 507 | return; 508 | } 509 | IF_VERBOSE { 510 | if (tfo_nsend >= 0) { 511 | LOGINF("[tcp_tproxy_accept_cb] tfo send to %s#%hu, nsend:%zd", g_server_ipstr, g_server_portno, tfo_nsend); 512 | } else { 513 | LOGINF("[tcp_tproxy_accept_cb] try to connect to %s#%hu ...", g_server_ipstr, g_server_portno); 514 | } 515 | } 516 | 517 | tcp_context_t *context = malloc(sizeof(*context)); 518 | 519 | /* if (watcher->events & EV_CUSTOM); then it is client watcher; fi */ 520 | evio_t *watcher = &context->client_watcher; 521 | ev_io_init(watcher, tcp_stream_payload_forward_cb, client_sockfd, EV_READ | EV_CUSTOM); 522 | 523 | /* build the ipv4/ipv6 proxy request (send to the socks5 proxy server) */ 524 | context->client_watcher.data = malloc(isipv4 ? sizeof(socks5_ipv4req_t) : sizeof(socks5_ipv6req_t)); 525 | context->client_length = isipv4 ? sizeof(socks5_ipv4req_t) : sizeof(socks5_ipv6req_t); 526 | socks5_proxy_request_make(context->client_watcher.data, &skaddr); 527 | 528 | watcher = &context->socks5_watcher; 529 | if (tfo_nsend >= 0 && (size_t)tfo_nsend >= tfo_datalen) { 530 | ev_io_init(watcher, tcp_socks5_recv_authresp_cb, socks5_sockfd, EV_READ); 531 | tfo_nsend = 0; /* reset to zero for next send */ 532 | } else { 533 | ev_io_init(watcher, tfo_nsend >= 0 ? tcp_socks5_send_authreq_cb : tcp_socks5_connect_cb, socks5_sockfd, EV_WRITE); 534 | tfo_nsend = tfo_nsend >= 0 ? tfo_nsend : 0; 535 | } 536 | ev_io_start(evloop, watcher); 537 | 538 | context->socks5_watcher.data = malloc(sizeof(socks5_ipv6resp_t)); 539 | context->socks5_length = (size_t)tfo_nsend; 540 | } 541 | 542 | static inline tcp_context_t* get_tcpctx_by_watcher(evio_t *watcher) { 543 | if (watcher->events & EV_CUSTOM) { 544 | return (void *)watcher - offsetof(tcp_context_t, client_watcher); 545 | } else { 546 | return (void *)watcher - offsetof(tcp_context_t, socks5_watcher); 547 | } 548 | } 549 | 550 | static inline void tcp_context_release(evloop_t *evloop, tcp_context_t *context, bool is_tcp_reset) { 551 | evio_t *client_watcher = &context->client_watcher; 552 | evio_t *socks5_watcher = &context->socks5_watcher; 553 | ev_io_stop(evloop, client_watcher); 554 | ev_io_stop(evloop, socks5_watcher); 555 | if (is_tcp_reset) { 556 | tcp_close_by_rst(client_watcher->fd); 557 | tcp_close_by_rst(socks5_watcher->fd); 558 | } else { 559 | close(client_watcher->fd); 560 | close(socks5_watcher->fd); 561 | } 562 | if (client_watcher->data || socks5_watcher->data) { 563 | free(client_watcher->data); 564 | free(socks5_watcher->data); 565 | } else { 566 | close(context->client_pipefd[0]); 567 | close(context->client_pipefd[1]); 568 | close(context->socks5_pipefd[0]); 569 | close(context->socks5_pipefd[1]); 570 | } 571 | free(context); 572 | } 573 | 574 | static void tcp_socks5_connect_cb(evloop_t *evloop, evio_t *socks5_watcher, int revents __attribute__((unused))) { 575 | if (tcp_has_error(socks5_watcher->fd)) { 576 | LOGERR("[tcp_socks5_connect_cb] connect to %s#%hu: %s", g_server_ipstr, g_server_portno, strerror(errno)); 577 | tcp_context_release(evloop, get_tcpctx_by_watcher(socks5_watcher), true); 578 | return; 579 | } 580 | IF_VERBOSE LOGINF("[tcp_socks5_connect_cb] connect to %s#%hu succeeded", g_server_ipstr, g_server_portno); 581 | ev_set_cb(socks5_watcher, tcp_socks5_send_authreq_cb); 582 | ev_invoke(evloop, socks5_watcher, EV_WRITE); 583 | } 584 | 585 | /* return: -1(error_occurred); 0(partial_sent); 1(completely_sent) */ 586 | static int tcp_socks5_send_request(const char *funcname, evloop_t *evloop, evio_t *socks5_watcher, const void *data, size_t datalen) { 587 | tcp_context_t *context = get_tcpctx_by_watcher(socks5_watcher); 588 | ssize_t nsend = send(socks5_watcher->fd, data + context->socks5_length, datalen - context->socks5_length, 0); 589 | if (nsend < 0) { 590 | if (errno != EAGAIN && errno != EWOULDBLOCK) { 591 | LOGERR("[%s] send to %s#%hu: %s", funcname, g_server_ipstr, g_server_portno, strerror(errno)); 592 | tcp_context_release(evloop, context, true); 593 | return -1; 594 | } 595 | return 0; 596 | } 597 | IF_VERBOSE LOGINF("[%s] send to %s#%hu, nsend:%zd", funcname, g_server_ipstr, g_server_portno, nsend); 598 | context->socks5_length += (size_t)nsend; 599 | if (context->socks5_length >= datalen) { 600 | context->socks5_length = 0; 601 | return 1; 602 | } 603 | return 0; 604 | } 605 | 606 | /* return: -1(error_occurred); 0(partial_recv); 1(completely_recv) */ 607 | static int tcp_socks5_recv_response(const char *funcname, evloop_t *evloop, evio_t *socks5_watcher, void *data, size_t datalen) { 608 | tcp_context_t *context = get_tcpctx_by_watcher(socks5_watcher); 609 | ssize_t nrecv = recv(socks5_watcher->fd, data + context->socks5_length, datalen - context->socks5_length, 0); 610 | if (nrecv < 0) { 611 | if (errno != EAGAIN && errno != EWOULDBLOCK) { 612 | LOGERR("[%s] recv from %s#%hu: %s", funcname, g_server_ipstr, g_server_portno, strerror(errno)); 613 | tcp_context_release(evloop, context, true); 614 | return -1; 615 | } 616 | return 0; 617 | } 618 | if (nrecv == 0) { 619 | LOGERR("[%s] recv from %s#%hu: connection is closed", funcname, g_server_ipstr, g_server_portno); 620 | tcp_context_release(evloop, context, true); 621 | return -1; 622 | } 623 | IF_VERBOSE LOGINF("[%s] recv from %s#%hu, nrecv:%zd", funcname, g_server_ipstr, g_server_portno, nrecv); 624 | context->socks5_length += (size_t)nrecv; 625 | if (context->socks5_length >= datalen) { 626 | context->socks5_length = 0; 627 | return 1; 628 | } 629 | return 0; 630 | } 631 | 632 | static void tcp_socks5_send_authreq_cb(evloop_t *evloop, evio_t *socks5_watcher, int revents __attribute__((unused))) { 633 | if (tcp_socks5_send_request("tcp_socks5_send_authreq_cb", evloop, socks5_watcher, &g_socks5_auth_request, sizeof(socks5_authreq_t)) != 1) { 634 | return; 635 | } 636 | ev_io_stop(evloop, socks5_watcher); 637 | ev_io_init(socks5_watcher, tcp_socks5_recv_authresp_cb, socks5_watcher->fd, EV_READ); 638 | ev_io_start(evloop, socks5_watcher); 639 | } 640 | 641 | static void tcp_socks5_recv_authresp_cb(evloop_t *evloop, evio_t *socks5_watcher, int revents __attribute__((unused))) { 642 | if (tcp_socks5_recv_response("tcp_socks5_recv_authresp_cb", evloop, socks5_watcher, socks5_watcher->data, sizeof(socks5_authresp_t)) != 1) { 643 | return; 644 | } 645 | if (!socks5_auth_response_check("tcp_socks5_recv_authresp_cb", socks5_watcher->data)) { 646 | tcp_context_release(evloop, get_tcpctx_by_watcher(socks5_watcher), true); 647 | return; 648 | } 649 | tcp_context_t *context = get_tcpctx_by_watcher(socks5_watcher); 650 | const void *data = g_socks5_usrpwd_requestlen ? &g_socks5_usrpwd_request : context->client_watcher.data; 651 | uint16_t datalen = g_socks5_usrpwd_requestlen ? g_socks5_usrpwd_requestlen : context->client_length; 652 | int ret = tcp_socks5_send_request("tcp_socks5_recv_authresp_cb", evloop, socks5_watcher, data, datalen); 653 | if (ret == 1) { 654 | ev_set_cb(socks5_watcher, g_socks5_usrpwd_requestlen ? tcp_socks5_recv_usrpwdresp_cb : tcp_socks5_recv_proxyresp_cb); 655 | if (!g_socks5_usrpwd_requestlen) context->client_length = sizeof(socks5_ipv4resp_t); // response_length 656 | } else if (ret == 0) { 657 | ev_io_stop(evloop, socks5_watcher); 658 | ev_io_init(socks5_watcher, g_socks5_usrpwd_requestlen ? tcp_socks5_send_usrpwdreq_cb : tcp_socks5_send_proxyreq_cb, socks5_watcher->fd, EV_WRITE); 659 | ev_io_start(evloop, socks5_watcher); 660 | } 661 | } 662 | 663 | static void tcp_socks5_send_usrpwdreq_cb(evloop_t *evloop, evio_t *socks5_watcher, int revents __attribute__((unused))) { 664 | if (tcp_socks5_send_request("tcp_socks5_send_usrpwdreq_cb", evloop, socks5_watcher, &g_socks5_usrpwd_request, g_socks5_usrpwd_requestlen) != 1) { 665 | return; 666 | } 667 | ev_io_stop(evloop, socks5_watcher); 668 | ev_io_init(socks5_watcher, tcp_socks5_recv_usrpwdresp_cb, socks5_watcher->fd, EV_READ); 669 | ev_io_start(evloop, socks5_watcher); 670 | } 671 | 672 | static void tcp_socks5_recv_usrpwdresp_cb(evloop_t *evloop, evio_t *socks5_watcher, int revents __attribute__((unused))) { 673 | if (tcp_socks5_recv_response("tcp_socks5_recv_usrpwdresp_cb", evloop, socks5_watcher, socks5_watcher->data, sizeof(socks5_usrpwdresp_t)) != 1) { 674 | return; 675 | } 676 | if (!socks5_usrpwd_response_check("tcp_socks5_recv_usrpwdresp_cb", socks5_watcher->data)) { 677 | tcp_context_release(evloop, get_tcpctx_by_watcher(socks5_watcher), true); 678 | return; 679 | } 680 | tcp_context_t *context = get_tcpctx_by_watcher(socks5_watcher); 681 | int ret = tcp_socks5_send_request("tcp_socks5_recv_usrpwdresp_cb", evloop, socks5_watcher, context->client_watcher.data, context->client_length); 682 | if (ret == 1) { 683 | ev_set_cb(socks5_watcher, tcp_socks5_recv_proxyresp_cb); 684 | context->client_length = sizeof(socks5_ipv4resp_t); // response_length 685 | } else if (ret == 0) { 686 | ev_io_stop(evloop, socks5_watcher); 687 | ev_io_init(socks5_watcher, tcp_socks5_send_proxyreq_cb, socks5_watcher->fd, EV_WRITE); 688 | ev_io_start(evloop, socks5_watcher); 689 | } 690 | } 691 | 692 | static void tcp_socks5_send_proxyreq_cb(evloop_t *evloop, evio_t *socks5_watcher, int revents __attribute__((unused))) { 693 | tcp_context_t *context = get_tcpctx_by_watcher(socks5_watcher); 694 | if (tcp_socks5_send_request("tcp_socks5_send_proxyreq_cb", evloop, socks5_watcher, context->client_watcher.data, context->client_length) != 1) { 695 | return; 696 | } 697 | ev_io_stop(evloop, socks5_watcher); 698 | ev_io_init(socks5_watcher, tcp_socks5_recv_proxyresp_cb, socks5_watcher->fd, EV_READ); 699 | ev_io_start(evloop, socks5_watcher); 700 | context->client_length = sizeof(socks5_ipv4resp_t); // response_length 701 | } 702 | 703 | static void tcp_socks5_recv_proxyresp_cb(evloop_t *evloop, evio_t *socks5_watcher, int revents __attribute__((unused))) { 704 | tcp_context_t *context = get_tcpctx_by_watcher(socks5_watcher); 705 | if (tcp_socks5_recv_response("tcp_socks5_recv_proxyresp_cb", evloop, socks5_watcher, socks5_watcher->data, context->client_length) != 1) { 706 | return; 707 | } 708 | if (context->client_length == sizeof(socks5_ipv4resp_t)) { 709 | if (!socks5_proxy_response_check("tcp_socks5_recv_proxyresp_cb", socks5_watcher->data)) { 710 | tcp_context_release(evloop, context, true); 711 | return; 712 | } 713 | if (((socks5_ipv4resp_t *)socks5_watcher->data)->addrtype == SOCKS5_ADDRTYPE_IPV6) { 714 | context->client_length = sizeof(socks5_ipv6resp_t); // response_length 715 | context->socks5_length = sizeof(socks5_ipv4resp_t); // response_nrecv 716 | return; 717 | } 718 | } 719 | context->client_length = 0; 720 | 721 | free(socks5_watcher->data); 722 | socks5_watcher->data = NULL; 723 | 724 | free(context->client_watcher.data); 725 | context->client_watcher.data = NULL; 726 | 727 | new_nonblock_pipefd(context->client_pipefd); 728 | new_nonblock_pipefd(context->socks5_pipefd); 729 | 730 | ev_io_start(evloop, &context->client_watcher); 731 | ev_set_cb(socks5_watcher, tcp_stream_payload_forward_cb); 732 | IF_VERBOSE LOGINF("[tcp_socks5_recv_proxyresp_cb] tunnel is ready, start forwarding ..."); 733 | } 734 | 735 | static void tcp_stream_payload_forward_cb(evloop_t *evloop, evio_t *self_watcher, int revents) { 736 | bool self_is_client = self_watcher->events & EV_CUSTOM; 737 | tcp_context_t *context = get_tcpctx_by_watcher(self_watcher); 738 | evio_t *peer_watcher = self_is_client ? &context->socks5_watcher : &context->client_watcher; 739 | 740 | if (revents & EV_READ) { 741 | int *self_pipefd = self_is_client ? context->client_pipefd : context->socks5_pipefd; 742 | ssize_t nrecv = splice(self_watcher->fd, NULL, self_pipefd[1], NULL, TCP_SPLICE_MAXLEN, SPLICE_F_MOVE | SPLICE_F_NONBLOCK); 743 | if (nrecv < 0) { 744 | if (errno != EAGAIN && errno != EWOULDBLOCK) { 745 | LOGERR("[tcp_stream_payload_forward_cb] recv from %s stream: %s", self_is_client ? "client" : "socks5", strerror(errno)); 746 | tcp_context_release(evloop, context, true); 747 | return; 748 | } 749 | goto DO_WRITE; // EAGAIN 750 | } 751 | if (nrecv == 0) { 752 | IF_VERBOSE LOGINF("[tcp_stream_payload_forward_cb] recv FIN from %s stream, release ctx", self_is_client ? "client" : "socks5"); 753 | tcp_context_release(evloop, context, false); 754 | return; 755 | } 756 | 757 | ssize_t nsend = splice(self_pipefd[0], NULL, peer_watcher->fd, NULL, nrecv, SPLICE_F_MOVE | SPLICE_F_NONBLOCK); 758 | if (nsend < 0) { 759 | if (errno != EAGAIN && errno != EWOULDBLOCK) { 760 | LOGERR("[tcp_stream_payload_forward_cb] send to %s stream: %s", self_is_client ? "socks5" : "client", strerror(errno)); 761 | tcp_context_release(evloop, context, true); 762 | return; 763 | } 764 | nsend = 0; // EAGAIN 765 | } 766 | if (nsend < nrecv) { 767 | *(self_is_client ? &context->client_length : &context->socks5_length) = (size_t)(nrecv - nsend); // remain_length 768 | 769 | ev_io_stop(evloop, self_watcher); 770 | ev_io_modify(self_watcher, self_watcher->events & ~EV_READ); 771 | if (self_watcher->events & EV_WRITE) ev_io_start(evloop, self_watcher); 772 | 773 | ev_io_stop(evloop, peer_watcher); 774 | ev_io_modify(peer_watcher, peer_watcher->events | EV_WRITE); 775 | ev_io_start(evloop, peer_watcher); 776 | } 777 | } 778 | 779 | DO_WRITE: 780 | if (revents & EV_WRITE) { 781 | int *peer_pipefd = self_is_client ? context->socks5_pipefd : context->client_pipefd; 782 | uint16_t remain_length = self_is_client ? context->socks5_length : context->client_length; 783 | 784 | ssize_t nsend = splice(peer_pipefd[0], NULL, self_watcher->fd, NULL, remain_length, SPLICE_F_MOVE | SPLICE_F_NONBLOCK); 785 | if (nsend < 0) { 786 | if (errno != EAGAIN && errno != EWOULDBLOCK) { 787 | LOGERR("[tcp_stream_payload_forward_cb] send to %s stream: %s", self_is_client ? "client" : "socks5", strerror(errno)); 788 | tcp_context_release(evloop, context, true); 789 | } 790 | return; 791 | } 792 | if (nsend == 0) return; // IGNORE 793 | 794 | remain_length -= (size_t)nsend; 795 | *(self_is_client ? &context->socks5_length : &context->client_length) = remain_length; 796 | 797 | if (remain_length <= 0) { 798 | ev_io_stop(evloop, self_watcher); 799 | ev_io_modify(self_watcher, self_watcher->events & ~EV_WRITE); 800 | if (self_watcher->events & EV_READ) ev_io_start(evloop, self_watcher); 801 | 802 | ev_io_stop(evloop, peer_watcher); 803 | ev_io_modify(peer_watcher, peer_watcher->events | EV_READ); 804 | ev_io_start(evloop, peer_watcher); 805 | } 806 | } 807 | } 808 | 809 | static void udp_tproxy_recvmsg_cb(evloop_t *evloop, evio_t *tprecv_watcher, int revents __attribute__((unused))) { 810 | bool isipv4 = tprecv_watcher->data; 811 | char msg_control_buffer[UDP_CTRLMESG_BUFSIZ] = {0}; 812 | skaddr6_t skaddr; char ipstr[IP6STRLEN]; portno_t portno; 813 | size_t headerlen = isipv4 ? sizeof(socks5_udp4msg_t) : sizeof(socks5_udp6msg_t); 814 | 815 | struct msghdr msg = { 816 | .msg_name = &skaddr, 817 | .msg_namelen = sizeof(skaddr), 818 | .msg_iov = &(struct iovec){ 819 | .iov_base = (void *)g_udp_dgram_buffer + headerlen, 820 | .iov_len = UDP_DATAGRAM_MAXSIZ - headerlen, 821 | }, 822 | .msg_iovlen = 1, 823 | .msg_control = msg_control_buffer, 824 | .msg_controllen = UDP_CTRLMESG_BUFSIZ, 825 | .msg_flags = 0, 826 | }; 827 | 828 | ssize_t nrecv = recvmsg(tprecv_watcher->fd, &msg, 0); 829 | if (nrecv < 0) { 830 | if (errno != EAGAIN && errno != EWOULDBLOCK) { 831 | LOGERR("[udp_tproxy_recvmsg_cb] recv from udp%s socket: %s", isipv4 ? "4" : "6", strerror(errno)); 832 | } 833 | return; 834 | } 835 | IF_VERBOSE { 836 | parse_socket_addr(&skaddr, ipstr, &portno); 837 | LOGINF("[udp_tproxy_recvmsg_cb] recv from %s#%hu, nrecv:%zd", ipstr, portno, nrecv); 838 | } 839 | 840 | ip_port_t key_ipport = {.ip = {0}, .port = 0}; 841 | if (isipv4) { 842 | key_ipport.ip.ip4 = ((skaddr4_t *)&skaddr)->sin_addr.s_addr; 843 | key_ipport.port = ((skaddr4_t *)&skaddr)->sin_port; 844 | } else { 845 | memcpy(&key_ipport.ip.ip6, &skaddr.sin6_addr.s6_addr, IP6BINLEN); 846 | key_ipport.port = skaddr.sin6_port; 847 | } 848 | 849 | if (!get_udp_orig_dstaddr(isipv4 ? AF_INET : AF_INET6, &msg, &skaddr)) { 850 | LOGERR("[udp_tproxy_recvmsg_cb] destination address not found in udp msg"); 851 | return; 852 | } 853 | 854 | socks5_udp4msg_t *udp4msg = (void *)g_udp_dgram_buffer; 855 | udp4msg->reserved = 0; 856 | udp4msg->fragment = 0; 857 | udp4msg->addrtype = isipv4 ? SOCKS5_ADDRTYPE_IPV4 : SOCKS5_ADDRTYPE_IPV6; 858 | if (isipv4) { 859 | udp4msg->ipaddr4 = ((skaddr4_t *)&skaddr)->sin_addr.s_addr; 860 | udp4msg->portnum = ((skaddr4_t *)&skaddr)->sin_port; 861 | } else { 862 | socks5_udp6msg_t *udp6msg = (void *)g_udp_dgram_buffer; 863 | memcpy(&udp6msg->ipaddr6, &skaddr.sin6_addr.s6_addr, IP6BINLEN); 864 | udp6msg->portnum = skaddr.sin6_port; 865 | } 866 | 867 | udp_socks5ctx_t *context = udp_socks5ctx_get(&g_udp_socks5ctx_table, &key_ipport); 868 | if (!context) { 869 | int tcp_sockfd = new_tcp_connect_sockfd(g_server_skaddr.sin6_family, g_tcp_syncnt_max); 870 | const void *tfo_data = (g_options & OPT_ENABLE_TFO_CONNECT) ? &g_socks5_auth_request : NULL; 871 | uint16_t tfo_datalen = (g_options & OPT_ENABLE_TFO_CONNECT) ? sizeof(socks5_authreq_t) : 0; 872 | ssize_t tfo_nsend = -1; /* if tfo connect succeed: tfo_nsend >= 0 */ 873 | 874 | if (!tcp_connect(tcp_sockfd, &g_server_skaddr, tfo_data, tfo_datalen, &tfo_nsend)) { 875 | LOGERR("[udp_tproxy_recvmsg_cb] connect to %s#%hu: %s", g_server_ipstr, g_server_portno, strerror(errno)); 876 | close(tcp_sockfd); 877 | return; 878 | } 879 | IF_VERBOSE { 880 | if (tfo_nsend >= 0) { 881 | LOGINF("[udp_tproxy_recvmsg_cb] tfo send to %s#%hu, nsend:%zd", g_server_ipstr, g_server_portno, tfo_nsend); 882 | } else { 883 | LOGINF("[udp_tproxy_recvmsg_cb] try to connect to %s#%hu ...", g_server_ipstr, g_server_portno); 884 | } 885 | } 886 | 887 | context = malloc(sizeof(*context)); 888 | memcpy(&context->key_ipport, &key_ipport, sizeof(key_ipport)); 889 | 890 | evio_t *watcher = &context->tcp_watcher; 891 | if (tfo_nsend >= 0 && (size_t)tfo_nsend >= tfo_datalen) { 892 | ev_io_init(watcher, udp_socks5_recv_authresp_cb, tcp_sockfd, EV_READ); 893 | tfo_nsend = 0; 894 | } else { 895 | ev_io_init(watcher, tfo_nsend >= 0 ? udp_socks5_send_authreq_cb : udp_socks5_connect_cb, tcp_sockfd, EV_WRITE); 896 | tfo_nsend = tfo_nsend >= 0 ? tfo_nsend : 0; 897 | } 898 | ev_io_start(evloop, watcher); 899 | context->tcp_watcher.data = malloc(2 + sizeof(socks5_ipv6resp_t)); 900 | *(uint16_t *)context->tcp_watcher.data = tfo_nsend; /* nsend or nrecv */ 901 | 902 | /* tunnel not ready if udp_watcher->data != NULL */ 903 | context->udp_watcher.data = malloc(2 + headerlen + nrecv); 904 | *(uint16_t *)context->udp_watcher.data = headerlen + nrecv; 905 | memcpy(context->udp_watcher.data + 2, g_udp_dgram_buffer, headerlen + nrecv); 906 | 907 | evtimer_t *timer = &context->idle_timer; 908 | ev_timer_init(timer, udp_socks5_context_timeout_cb, 0, g_udp_idletimeout_sec); 909 | timer->data = (void *)sizeof(socks5_ipv4resp_t); // response_length 910 | 911 | udp_socks5ctx_t *del_context = udp_socks5ctx_add(&g_udp_socks5ctx_table, context); 912 | if (del_context) ev_invoke(evloop, &del_context->idle_timer, EV_CUSTOM); 913 | return; 914 | } 915 | if (context->udp_watcher.data) { 916 | IF_VERBOSE LOGINF("[udp_tproxy_recvmsg_cb] tunnel is not ready, discard this msg"); 917 | return; 918 | } 919 | 920 | ev_timer_again(evloop, &context->idle_timer); 921 | nrecv = send(context->udp_watcher.fd, g_udp_dgram_buffer, headerlen + nrecv, 0); 922 | if (nrecv < 0) { 923 | parse_socket_addr(&skaddr, ipstr, &portno); 924 | LOGERR("[udp_tproxy_recvmsg_cb] send to %s#%hu: %s", ipstr, portno, strerror(errno)); 925 | return; 926 | } 927 | IF_VERBOSE { 928 | parse_socket_addr(&skaddr, ipstr, &portno); 929 | LOGINF("[udp_tproxy_recvmsg_cb] send to %s#%hu, nsend:%zd", ipstr, portno, nrecv); 930 | } 931 | } 932 | 933 | static inline udp_socks5ctx_t* get_udpsk5ctx_by_tcp(evio_t *tcp_watcher) { 934 | return (void *)tcp_watcher - offsetof(udp_socks5ctx_t, tcp_watcher); 935 | } 936 | 937 | static inline void udp_socks5ctx_release(evloop_t *evloop, udp_socks5ctx_t *context) { 938 | ev_invoke(evloop, &context->idle_timer, EV_CUSTOM); 939 | } 940 | 941 | static void udp_socks5_connect_cb(evloop_t *evloop, evio_t *tcp_watcher, int revents __attribute__((unused))) { 942 | if (tcp_has_error(tcp_watcher->fd)) { 943 | LOGERR("[udp_socks5_connect_cb] connect to %s#%hu: %s", g_server_ipstr, g_server_portno, strerror(errno)); 944 | udp_socks5ctx_release(evloop, get_udpsk5ctx_by_tcp(tcp_watcher)); 945 | return; 946 | } 947 | IF_VERBOSE LOGINF("[udp_socks5_connect_cb] connect to %s#%hu succeeded", g_server_ipstr, g_server_portno); 948 | ev_set_cb(tcp_watcher, udp_socks5_send_authreq_cb); 949 | ev_invoke(evloop, tcp_watcher, EV_WRITE); 950 | } 951 | 952 | /* return: -1(error_occurred); 0(partial_sent); 1(completely_sent) */ 953 | static int udp_socks5_send_request(const char *funcname, evloop_t *evloop, evio_t *tcp_watcher, const void *data, size_t datalen) { 954 | uint16_t *nsend = tcp_watcher->data; 955 | ssize_t n = send(tcp_watcher->fd, data + *nsend, datalen - *nsend, 0); 956 | if (n < 0) { 957 | if (errno != EAGAIN && errno != EWOULDBLOCK) { 958 | LOGERR("[%s] send to %s#%hu: %s", funcname, g_server_ipstr, g_server_portno, strerror(errno)); 959 | udp_socks5ctx_release(evloop, get_udpsk5ctx_by_tcp(tcp_watcher)); 960 | return -1; 961 | } 962 | return 0; 963 | } 964 | IF_VERBOSE LOGINF("[%s] send to %s#%hu, nsend:%zd", funcname, g_server_ipstr, g_server_portno, n); 965 | *nsend += (size_t)n; 966 | if (*nsend >= datalen) { 967 | *nsend = 0; 968 | return 1; 969 | } 970 | return 0; 971 | } 972 | 973 | /* return: -1(error_occurred); 0(partial_recv); 1(completely_recv) */ 974 | static int udp_socks5_recv_response(const char *funcname, evloop_t *evloop, evio_t *tcp_watcher, void *data, size_t datalen) { 975 | uint16_t *nrecv = tcp_watcher->data; 976 | ssize_t n = recv(tcp_watcher->fd, data + *nrecv, datalen - *nrecv, 0); 977 | if (n < 0) { 978 | if (errno != EAGAIN && errno != EWOULDBLOCK) { 979 | LOGERR("[%s] recv from %s#%hu: %s", funcname, g_server_ipstr, g_server_portno, strerror(errno)); 980 | udp_socks5ctx_release(evloop, get_udpsk5ctx_by_tcp(tcp_watcher)); 981 | return -1; 982 | } 983 | return 0; 984 | } 985 | if (n == 0) { 986 | LOGERR("[%s] recv from %s#%hu: connection is closed", funcname, g_server_ipstr, g_server_portno); 987 | udp_socks5ctx_release(evloop, get_udpsk5ctx_by_tcp(tcp_watcher)); 988 | return -1; 989 | } 990 | IF_VERBOSE LOGINF("[%s] recv from %s#%hu, nrecv:%zd", funcname, g_server_ipstr, g_server_portno, n); 991 | *nrecv += (size_t)n; 992 | if (*nrecv >= datalen) { 993 | *nrecv = 0; 994 | return 1; 995 | } 996 | return 0; 997 | } 998 | 999 | static void udp_socks5_send_authreq_cb(evloop_t *evloop, evio_t *tcp_watcher, int revents __attribute__((unused))) { 1000 | if (udp_socks5_send_request("udp_socks5_send_authreq_cb", evloop, tcp_watcher, &g_socks5_auth_request, sizeof(socks5_authreq_t)) != 1) { 1001 | return; 1002 | } 1003 | ev_io_stop(evloop, tcp_watcher); 1004 | ev_io_init(tcp_watcher, udp_socks5_recv_authresp_cb, tcp_watcher->fd, EV_READ); 1005 | ev_io_start(evloop, tcp_watcher); 1006 | } 1007 | 1008 | static void udp_socks5_recv_authresp_cb(evloop_t *evloop, evio_t *tcp_watcher, int revents __attribute__((unused))) { 1009 | if (udp_socks5_recv_response("udp_socks5_recv_authresp_cb", evloop, tcp_watcher, tcp_watcher->data + 2, sizeof(socks5_authresp_t)) != 1) { 1010 | return; 1011 | } 1012 | if (!socks5_auth_response_check("udp_socks5_recv_authresp_cb", tcp_watcher->data + 2)) { 1013 | udp_socks5ctx_release(evloop, get_udpsk5ctx_by_tcp(tcp_watcher)); 1014 | return; 1015 | } 1016 | const void *data; uint16_t datalen; 1017 | if (g_socks5_usrpwd_requestlen) { 1018 | data = &g_socks5_usrpwd_request; 1019 | datalen = g_socks5_usrpwd_requestlen; 1020 | } else { 1021 | udp_socks5ctx_t *context = get_udpsk5ctx_by_tcp(tcp_watcher); 1022 | bool isipv4 = ((socks5_udp4msg_t *)(context->udp_watcher.data + 2))->addrtype == SOCKS5_ADDRTYPE_IPV4; 1023 | data = isipv4 ? (void *)&G_SOCKS5_UDP4_REQUEST : (void *)&G_SOCKS5_UDP6_REQUEST; 1024 | datalen = isipv4 ? sizeof(socks5_ipv4req_t) : sizeof(socks5_ipv6req_t); 1025 | } 1026 | int ret = udp_socks5_send_request("udp_socks5_recv_authresp_cb", evloop, tcp_watcher, data, datalen); 1027 | if (ret == 1) { 1028 | ev_set_cb(tcp_watcher, g_socks5_usrpwd_requestlen ? udp_socks5_recv_usrpwdresp_cb : udp_socks5_recv_proxyresp_cb); 1029 | } else if (ret == 0) { 1030 | ev_io_stop(evloop, tcp_watcher); 1031 | ev_io_init(tcp_watcher, g_socks5_usrpwd_requestlen ? udp_socks5_send_usrpwdreq_cb : udp_socks5_send_proxyreq_cb, tcp_watcher->fd, EV_WRITE); 1032 | ev_io_start(evloop, tcp_watcher); 1033 | } 1034 | } 1035 | 1036 | static void udp_socks5_send_usrpwdreq_cb(evloop_t *evloop, evio_t *tcp_watcher, int revents __attribute__((unused))) { 1037 | if (udp_socks5_send_request("udp_socks5_send_usrpwdreq_cb", evloop, tcp_watcher, &g_socks5_usrpwd_request, g_socks5_usrpwd_requestlen) != 1) { 1038 | return; 1039 | } 1040 | ev_io_stop(evloop, tcp_watcher); 1041 | ev_io_init(tcp_watcher, udp_socks5_recv_usrpwdresp_cb, tcp_watcher->fd, EV_READ); 1042 | ev_io_start(evloop, tcp_watcher); 1043 | } 1044 | 1045 | static void udp_socks5_recv_usrpwdresp_cb(evloop_t *evloop, evio_t *tcp_watcher, int revents __attribute__((unused))) { 1046 | if (udp_socks5_recv_response("udp_socks5_recv_usrpwdresp_cb", evloop, tcp_watcher, tcp_watcher->data + 2, sizeof(socks5_usrpwdresp_t)) != 1) { 1047 | return; 1048 | } 1049 | if (!socks5_usrpwd_response_check("udp_socks5_recv_usrpwdresp_cb", tcp_watcher->data + 2)) { 1050 | udp_socks5ctx_release(evloop, get_udpsk5ctx_by_tcp(tcp_watcher)); 1051 | return; 1052 | } 1053 | udp_socks5ctx_t *context = get_udpsk5ctx_by_tcp(tcp_watcher); 1054 | bool isipv4 = ((socks5_udp4msg_t *)(context->udp_watcher.data + 2))->addrtype == SOCKS5_ADDRTYPE_IPV4; 1055 | const void *data = isipv4 ? (void *)&G_SOCKS5_UDP4_REQUEST : (void *)&G_SOCKS5_UDP6_REQUEST; 1056 | uint16_t datalen = isipv4 ? sizeof(socks5_ipv4req_t) : sizeof(socks5_ipv6req_t); 1057 | int ret = udp_socks5_send_request("udp_socks5_recv_usrpwdresp_cb", evloop, tcp_watcher, data, datalen); 1058 | if (ret == 1) { 1059 | ev_set_cb(tcp_watcher, udp_socks5_recv_proxyresp_cb); 1060 | } else if (ret == 0) { 1061 | ev_io_stop(evloop, tcp_watcher); 1062 | ev_io_init(tcp_watcher, udp_socks5_send_proxyreq_cb, tcp_watcher->fd, EV_WRITE); 1063 | ev_io_start(evloop, tcp_watcher); 1064 | } 1065 | } 1066 | 1067 | static void udp_socks5_send_proxyreq_cb(evloop_t *evloop, evio_t *tcp_watcher, int revents __attribute__((unused))) { 1068 | udp_socks5ctx_t *context = get_udpsk5ctx_by_tcp(tcp_watcher); 1069 | bool isipv4 = ((socks5_udp4msg_t *)(context->udp_watcher.data + 2))->addrtype == SOCKS5_ADDRTYPE_IPV4; 1070 | const void *request = isipv4 ? (void *)&G_SOCKS5_UDP4_REQUEST : (void *)&G_SOCKS5_UDP6_REQUEST; 1071 | uint16_t requestlen = isipv4 ? sizeof(socks5_ipv4req_t) : sizeof(socks5_ipv6req_t); 1072 | if (udp_socks5_send_request("udp_socks5_send_proxyreq_cb", evloop, tcp_watcher, request, requestlen) != 1) { 1073 | return; 1074 | } 1075 | ev_io_stop(evloop, tcp_watcher); 1076 | ev_io_init(tcp_watcher, udp_socks5_recv_proxyresp_cb, tcp_watcher->fd, EV_READ); 1077 | ev_io_start(evloop, tcp_watcher); 1078 | } 1079 | 1080 | static void udp_socks5_recv_proxyresp_cb(evloop_t *evloop, evio_t *tcp_watcher, int revents __attribute__((unused))) { 1081 | udp_socks5ctx_t *context = get_udpsk5ctx_by_tcp(tcp_watcher); 1082 | if (udp_socks5_recv_response("udp_socks5_recv_proxyresp_cb", evloop, tcp_watcher, tcp_watcher->data + 2, (uintptr_t)context->idle_timer.data) != 1) { 1083 | return; 1084 | } 1085 | if ((uintptr_t)context->idle_timer.data == sizeof(socks5_ipv4resp_t)) { 1086 | if (!socks5_proxy_response_check("udp_socks5_recv_proxyresp_cb", tcp_watcher->data + 2)) { 1087 | udp_socks5ctx_release(evloop, context); 1088 | return; 1089 | } 1090 | if (((socks5_ipv4resp_t *)(tcp_watcher->data + 2))->addrtype == SOCKS5_ADDRTYPE_IPV6) { 1091 | context->idle_timer.data = (void *)sizeof(socks5_ipv6resp_t); // response_length 1092 | *(uint16_t *)tcp_watcher->data = sizeof(socks5_ipv4resp_t); // response_nrecv 1093 | return; 1094 | } 1095 | } 1096 | bool resp_isipv4 = (uintptr_t)context->idle_timer.data == sizeof(socks5_ipv4resp_t); 1097 | 1098 | /* the udp relay port (from the assoc response) */ 1099 | portno_t relay_port = resp_isipv4 ? 1100 | ((socks5_ipv4resp_t *)(tcp_watcher->data + 2))->portnum : 1101 | ((socks5_ipv6resp_t *)(tcp_watcher->data + 2))->portnum; 1102 | 1103 | /* the address is usually the same as the socks5 server address (except for the port) */ 1104 | skaddr6_t relay_addr; 1105 | memcpy(&relay_addr, &g_server_skaddr, sizeof(g_server_skaddr)); 1106 | 1107 | /* update the port to the udp relay port */ 1108 | bool relay_isipv4 = relay_addr.sin6_family == AF_INET; 1109 | if (relay_isipv4) 1110 | ((skaddr4_t *)&relay_addr)->sin_port = relay_port; 1111 | else 1112 | relay_addr.sin6_port = relay_port; 1113 | 1114 | /* connect to the socks5 udp relay endpoint */ 1115 | int udp_sockfd = new_udp_normal_sockfd(relay_addr.sin6_family); 1116 | if (connect(udp_sockfd, (void *)&relay_addr, relay_isipv4 ? sizeof(skaddr4_t) : sizeof(skaddr6_t)) < 0) { 1117 | char ipstr[IP6STRLEN]; portno_t portno; 1118 | parse_socket_addr(&relay_addr, ipstr, &portno); 1119 | LOGERR("[udp_socks5_recv_proxyresp_cb] connect to udp://%s#%u: %s", ipstr, (unsigned)portno, strerror(errno)); 1120 | udp_socks5ctx_release(evloop, context); 1121 | close(udp_sockfd); 1122 | return; 1123 | } 1124 | 1125 | ssize_t nsend = send(udp_sockfd, context->udp_watcher.data + 2, *(uint16_t *)context->udp_watcher.data, 0); 1126 | if (nsend < 0 || g_verbose) { 1127 | char ipstr[IP6STRLEN]; portno_t portno; 1128 | if (((socks5_udp4msg_t *)(context->udp_watcher.data + 2))->addrtype == SOCKS5_ADDRTYPE_IPV4) { 1129 | socks5_udp4msg_t *udp4msg = context->udp_watcher.data + 2; 1130 | inet_ntop(AF_INET, &udp4msg->ipaddr4, ipstr, IP6STRLEN); 1131 | portno = ntohs(udp4msg->portnum); 1132 | } else { 1133 | socks5_udp6msg_t *udp6msg = context->udp_watcher.data + 2; 1134 | inet_ntop(AF_INET6, &udp6msg->ipaddr6, ipstr, IP6STRLEN); 1135 | portno = ntohs(udp6msg->portnum); 1136 | } 1137 | if (nsend < 0) { 1138 | LOGERR("[udp_socks5_recv_proxyresp_cb] send to %s#%hu: %s", ipstr, portno, strerror(errno)); 1139 | } else { 1140 | LOGINF("[udp_socks5_recv_proxyresp_cb] send to %s#%hu, nsend:%zd", ipstr, portno, nsend); 1141 | } 1142 | } 1143 | 1144 | ev_set_cb(tcp_watcher, udp_socks5_recv_tcpmessage_cb); 1145 | free(tcp_watcher->data); 1146 | tcp_watcher->data = NULL; 1147 | 1148 | evio_t *watcher = &context->udp_watcher; 1149 | ev_io_init(watcher, udp_socks5_recv_udpmessage_cb, udp_sockfd, EV_READ); 1150 | ev_io_start(evloop, watcher); 1151 | free(watcher->data); /* udp_watcher->data */ 1152 | watcher->data = NULL; /* udp_watcher->data */ 1153 | 1154 | ev_timer_again(evloop, &context->idle_timer); 1155 | udp_socks5ctx_use(&g_udp_socks5ctx_table, context); 1156 | } 1157 | 1158 | static void udp_socks5_recv_tcpmessage_cb(evloop_t *evloop, evio_t *tcp_watcher, int revents __attribute__((unused))) { 1159 | ssize_t nrecv = recv(tcp_watcher->fd, (char [1]){0}, 1, 0); 1160 | if (nrecv > 0) { 1161 | LOGERR("[udp_socks5_recv_tcpmessage_cb] recv unknown msg from socks5 server, release ctx"); 1162 | udp_socks5ctx_release(evloop, get_udpsk5ctx_by_tcp(tcp_watcher)); 1163 | } else if (nrecv == 0) { 1164 | IF_VERBOSE LOGINF("[udp_socks5_recv_tcpmessage_cb] recv FIN from socks5 server, release ctx"); 1165 | udp_socks5ctx_release(evloop, get_udpsk5ctx_by_tcp(tcp_watcher)); 1166 | } else if (errno != EAGAIN && errno != EWOULDBLOCK) { 1167 | LOGERR("[udp_socks5_recv_tcpmessage_cb] recv from socks5 server: %s", strerror(errno)); 1168 | udp_socks5ctx_release(evloop, get_udpsk5ctx_by_tcp(tcp_watcher)); 1169 | } 1170 | } 1171 | 1172 | static void udp_socks5_recv_udpmessage_cb(evloop_t *evloop, evio_t *udp_watcher, int revents __attribute__((unused))) { 1173 | ssize_t nrecv = recv(udp_watcher->fd, g_udp_dgram_buffer, UDP_DATAGRAM_MAXSIZ, 0); 1174 | if (nrecv < 0) { 1175 | if (errno != EAGAIN && errno != EWOULDBLOCK) { 1176 | LOGERR("[udp_socks5_recv_udpmessage_cb] recv from socks5 server: %s", strerror(errno)); 1177 | } 1178 | return; 1179 | } 1180 | if ((size_t)nrecv < sizeof(socks5_udp4msg_t)) { 1181 | LOGERR("[udp_socks5_recv_udpmessage_cb] recv from socks5 server: message too small"); 1182 | return; 1183 | } 1184 | socks5_udp4msg_t *udp4msg = (void *)g_udp_dgram_buffer; 1185 | bool isipv4 = udp4msg->addrtype == SOCKS5_ADDRTYPE_IPV4; 1186 | if (!isipv4 && (size_t)nrecv < sizeof(socks5_udp6msg_t)) { 1187 | LOGERR("[udp_socks5_recv_udpmessage_cb] recv from socks5 server: message too small"); 1188 | return; 1189 | } 1190 | 1191 | udp_socks5ctx_t *socks5ctx = (void *)udp_watcher - offsetof(udp_socks5ctx_t, udp_watcher); 1192 | udp_socks5ctx_use(&g_udp_socks5ctx_table, socks5ctx); 1193 | ev_timer_again(evloop, &socks5ctx->idle_timer); 1194 | 1195 | ip_port_t fromipport = {.ip = {0}, .port = 0}; 1196 | if (isipv4) { 1197 | fromipport.ip.ip4 = udp4msg->ipaddr4; 1198 | fromipport.port = udp4msg->portnum; 1199 | } else { 1200 | socks5_udp6msg_t *udp6msg = (void *)g_udp_dgram_buffer; 1201 | memcpy(&fromipport.ip.ip6, &udp6msg->ipaddr6, IP6BINLEN); 1202 | fromipport.port = udp6msg->portnum; 1203 | } 1204 | 1205 | char ipstr[IP6STRLEN]; portno_t portno; 1206 | IF_VERBOSE { 1207 | inet_ntop(isipv4 ? AF_INET : AF_INET6, isipv4 ? (void *)&fromipport.ip.ip4 : (void *)&fromipport.ip.ip6, ipstr, IP6STRLEN); 1208 | portno = ntohs(fromipport.port); 1209 | LOGINF("[udp_socks5_recv_udpmessage_cb] recv from %s#%hu, nrecv:%zd", ipstr, portno, nrecv); 1210 | } 1211 | 1212 | udp_tproxyctx_t *tproxyctx = udp_tproxyctx_get(&g_udp_tproxyctx_table, &fromipport); 1213 | if (!tproxyctx) { 1214 | skaddr6_t fromskaddr = {0}; 1215 | if (isipv4) { 1216 | skaddr4_t *addr = (void *)&fromskaddr; 1217 | addr->sin_family = AF_INET; 1218 | addr->sin_addr.s_addr = fromipport.ip.ip4; 1219 | addr->sin_port = fromipport.port; 1220 | } else { 1221 | fromskaddr.sin6_family = AF_INET6; 1222 | memcpy(&fromskaddr.sin6_addr.s6_addr, &fromipport.ip.ip6, IP6BINLEN); 1223 | fromskaddr.sin6_port = fromipport.port; 1224 | } 1225 | int tproxy_sockfd = new_udp_tpsend_sockfd(isipv4 ? AF_INET : AF_INET6); 1226 | if (bind(tproxy_sockfd, (void *)&fromskaddr, isipv4 ? sizeof(skaddr4_t) : sizeof(skaddr6_t)) < 0) { 1227 | LOGERR("[udp_socks5_recv_udpmessage_cb] bind tproxy reply address: %s", strerror(errno)); 1228 | close(tproxy_sockfd); 1229 | return; 1230 | } 1231 | tproxyctx = malloc(sizeof(*tproxyctx)); 1232 | memcpy(&tproxyctx->key_ipport, &fromipport, sizeof(fromipport)); 1233 | tproxyctx->udp_sockfd = tproxy_sockfd; 1234 | evtimer_t *timer = &tproxyctx->idle_timer; 1235 | ev_timer_init(timer, udp_tproxy_context_timeout_cb, 0, g_udp_idletimeout_sec); 1236 | udp_tproxyctx_t *del_context = udp_tproxyctx_add(&g_udp_tproxyctx_table, tproxyctx); 1237 | if (del_context) ev_invoke(evloop, &del_context->idle_timer, EV_CUSTOM); 1238 | } 1239 | ev_timer_again(evloop, &tproxyctx->idle_timer); 1240 | 1241 | ip_port_t *toipport = &socks5ctx->key_ipport; 1242 | skaddr6_t toskaddr = {0}; 1243 | if (isipv4) { 1244 | skaddr4_t *addr = (void *)&toskaddr; 1245 | addr->sin_family = AF_INET; 1246 | addr->sin_addr.s_addr = toipport->ip.ip4; 1247 | addr->sin_port = toipport->port; 1248 | } else { 1249 | toskaddr.sin6_family = AF_INET6; 1250 | memcpy(&toskaddr.sin6_addr.s6_addr, &toipport->ip.ip6, IP6BINLEN); 1251 | toskaddr.sin6_port = toipport->port; 1252 | } 1253 | 1254 | size_t headerlen = isipv4 ? sizeof(socks5_udp4msg_t) : sizeof(socks5_udp6msg_t); 1255 | nrecv = sendto(tproxyctx->udp_sockfd, (void *)g_udp_dgram_buffer + headerlen, nrecv - headerlen, 0, (void *)&toskaddr, isipv4 ? sizeof(skaddr4_t) : sizeof(skaddr6_t)); 1256 | if (nrecv < 0) { 1257 | parse_socket_addr(&toskaddr, ipstr, &portno); 1258 | LOGERR("[udp_socks5_recv_udpmessage_cb] send to %s#%hu: %s", ipstr, portno, strerror(errno)); 1259 | return; 1260 | } 1261 | IF_VERBOSE { 1262 | parse_socket_addr(&toskaddr, ipstr, &portno); 1263 | LOGINF("[udp_socks5_recv_udpmessage_cb] send to %s#%hu, nsend:%zd", ipstr, portno, nrecv); 1264 | } 1265 | } 1266 | 1267 | static void udp_socks5_context_timeout_cb(evloop_t *evloop, evtimer_t *idle_timer, int revents) { 1268 | IF_VERBOSE LOGINF("[udp_socks5_context_timeout_cb] context will be released, reason: %s", revents & EV_CUSTOM ? "manual" : "timeout"); 1269 | 1270 | udp_socks5ctx_t *context = (void *)idle_timer - offsetof(udp_socks5ctx_t, idle_timer); 1271 | udp_socks5ctx_del(&g_udp_socks5ctx_table, context); 1272 | 1273 | ev_timer_stop(evloop, idle_timer); 1274 | 1275 | ev_io_stop(evloop, &context->tcp_watcher); 1276 | close(context->tcp_watcher.fd); 1277 | free(context->tcp_watcher.data); 1278 | 1279 | if (context->udp_watcher.data) { 1280 | free(context->udp_watcher.data); 1281 | } else { 1282 | ev_io_stop(evloop, &context->udp_watcher); 1283 | close(context->udp_watcher.fd); 1284 | } 1285 | 1286 | free(context); 1287 | } 1288 | 1289 | static void udp_tproxy_context_timeout_cb(evloop_t *evloop, evtimer_t *idle_timer, int revents) { 1290 | IF_VERBOSE LOGINF("[udp_tproxy_context_timeout_cb] context will be released, reason: %s", revents & EV_CUSTOM ? "manual" : "timeout"); 1291 | 1292 | udp_tproxyctx_t *context = (void *)idle_timer - offsetof(udp_tproxyctx_t, idle_timer); 1293 | udp_tproxyctx_del(&g_udp_tproxyctx_table, context); 1294 | 1295 | ev_timer_stop(evloop, idle_timer); 1296 | close(context->udp_sockfd); 1297 | free(context); 1298 | } 1299 | -------------------------------------------------------------------------------- /src/logutils.h: -------------------------------------------------------------------------------- 1 | #ifndef IPT2SOCKS_LOGUTILS_H 2 | #define IPT2SOCKS_LOGUTILS_H 3 | 4 | #define _GNU_SOURCE 5 | #include 6 | #include 7 | 8 | #define LOGINF(fmt, ...) \ 9 | do { \ 10 | struct tm *tm = localtime_r(&(time_t){time(NULL)}, &(struct tm){0}); \ 11 | printf("\e[1;32m%04d-%02d-%02d %02d:%02d:%02d INF:\e[0m " fmt "\n", \ 12 | tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, \ 13 | tm->tm_hour, tm->tm_min, tm->tm_sec, \ 14 | ##__VA_ARGS__); \ 15 | } while (0) 16 | 17 | #define LOGERR(fmt, ...) \ 18 | do { \ 19 | struct tm *tm = localtime_r(&(time_t){time(NULL)}, &(struct tm){0}); \ 20 | printf("\e[1;35m%04d-%02d-%02d %02d:%02d:%02d ERR:\e[0m " fmt "\n", \ 21 | tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, \ 22 | tm->tm_hour, tm->tm_min, tm->tm_sec, \ 23 | ##__VA_ARGS__); \ 24 | } while (0) 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/lrucache.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include "lrucache.h" 3 | 4 | static uint16_t g_lrucache_maxsize = 256; 5 | 6 | uint16_t lrucache_get_maxsize(void) { 7 | return g_lrucache_maxsize; 8 | } 9 | void lrucache_set_maxsize(uint16_t maxsize) { 10 | g_lrucache_maxsize = maxsize; 11 | } 12 | 13 | udp_socks5ctx_t* udp_socks5ctx_add(udp_socks5ctx_t **cache, udp_socks5ctx_t *entry) { 14 | MYHASH_ADD(*cache, entry, &entry->key_ipport, sizeof(entry->key_ipport)); 15 | if (MYHASH_CNT(*cache) > g_lrucache_maxsize) { 16 | udp_socks5ctx_t *curentry = NULL, *tmpentry = NULL; 17 | MYHASH_FOR(*cache, curentry, tmpentry) { 18 | MYHASH_DEL(*cache, curentry); 19 | return curentry; 20 | } 21 | } 22 | return NULL; 23 | } 24 | udp_tproxyctx_t* udp_tproxyctx_add(udp_tproxyctx_t **cache, udp_tproxyctx_t *entry) { 25 | MYHASH_ADD(*cache, entry, &entry->key_ipport, sizeof(entry->key_ipport)); 26 | if (MYHASH_CNT(*cache) > g_lrucache_maxsize) { 27 | udp_tproxyctx_t *curentry = NULL, *tmpentry = NULL; 28 | MYHASH_FOR(*cache, curentry, tmpentry) { 29 | MYHASH_DEL(*cache, curentry); 30 | return curentry; 31 | } 32 | } 33 | return NULL; 34 | } 35 | 36 | udp_socks5ctx_t* udp_socks5ctx_get(udp_socks5ctx_t **cache, const ip_port_t *keyptr) { 37 | udp_socks5ctx_t *entry = NULL; 38 | MYHASH_GET(*cache, entry, keyptr, sizeof(ip_port_t)); 39 | if (entry) { 40 | MYHASH_DEL(*cache, entry); 41 | MYHASH_ADD(*cache, entry, &entry->key_ipport, sizeof(entry->key_ipport)); 42 | } 43 | return entry; 44 | } 45 | udp_tproxyctx_t* udp_tproxyctx_get(udp_tproxyctx_t **cache, const ip_port_t *keyptr) { 46 | udp_tproxyctx_t *entry = NULL; 47 | MYHASH_GET(*cache, entry, keyptr, sizeof(ip_port_t)); 48 | if (entry) { 49 | MYHASH_DEL(*cache, entry); 50 | MYHASH_ADD(*cache, entry, &entry->key_ipport, sizeof(entry->key_ipport)); 51 | } 52 | return entry; 53 | } 54 | 55 | void udp_socks5ctx_use(udp_socks5ctx_t **cache, udp_socks5ctx_t *entry) { 56 | MYHASH_DEL(*cache, entry); 57 | MYHASH_ADD(*cache, entry, &entry->key_ipport, sizeof(entry->key_ipport)); 58 | } 59 | void udp_tproxyctx_use(udp_tproxyctx_t **cache, udp_tproxyctx_t *entry) { 60 | MYHASH_DEL(*cache, entry); 61 | MYHASH_ADD(*cache, entry, &entry->key_ipport, sizeof(entry->key_ipport)); 62 | } 63 | 64 | void udp_socks5ctx_del(udp_socks5ctx_t **cache, udp_socks5ctx_t *entry) { 65 | MYHASH_DEL(*cache, entry); 66 | } 67 | void udp_tproxyctx_del(udp_tproxyctx_t **cache, udp_tproxyctx_t *entry) { 68 | MYHASH_DEL(*cache, entry); 69 | } 70 | -------------------------------------------------------------------------------- /src/lrucache.h: -------------------------------------------------------------------------------- 1 | #ifndef IPT2SOCKS_LRUCACHE_H 2 | #define IPT2SOCKS_LRUCACHE_H 3 | 4 | #define _GNU_SOURCE 5 | #include "uthash.h" 6 | #include "netutils.h" 7 | #include "../libev/ev.h" 8 | 9 | typedef struct { 10 | ip_port_t key_ipport; // (local) source socket address 11 | evio_t tcp_watcher; // .data: len(16bit) | recvbuff 12 | evio_t udp_watcher; // .data: len(16bit) | firstmsg 13 | evtimer_t idle_timer; 14 | myhash_hh hh; 15 | } udp_socks5ctx_t; 16 | 17 | typedef struct { 18 | ip_port_t key_ipport; // (remote) source socket address 19 | int udp_sockfd; // bind the above socket address 20 | evtimer_t idle_timer; 21 | myhash_hh hh; 22 | } udp_tproxyctx_t; 23 | 24 | uint16_t lrucache_get_maxsize(void); 25 | void lrucache_set_maxsize(uint16_t maxsize); 26 | 27 | /* return the removed hashentry pointer */ 28 | udp_socks5ctx_t* udp_socks5ctx_add(udp_socks5ctx_t **cache, udp_socks5ctx_t *entry); 29 | udp_tproxyctx_t* udp_tproxyctx_add(udp_tproxyctx_t **cache, udp_tproxyctx_t *entry); 30 | 31 | udp_socks5ctx_t* udp_socks5ctx_get(udp_socks5ctx_t **cache, const ip_port_t *keyptr); 32 | udp_tproxyctx_t* udp_tproxyctx_get(udp_tproxyctx_t **cache, const ip_port_t *keyptr); 33 | 34 | void udp_socks5ctx_use(udp_socks5ctx_t **cache, udp_socks5ctx_t *entry); 35 | void udp_tproxyctx_use(udp_tproxyctx_t **cache, udp_tproxyctx_t *entry); 36 | 37 | void udp_socks5ctx_del(udp_socks5ctx_t **cache, udp_socks5ctx_t *entry); 38 | void udp_tproxyctx_del(udp_tproxyctx_t **cache, udp_tproxyctx_t *entry); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/netutils.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include "netutils.h" 3 | #include "logutils.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #ifndef PATH_MAX 17 | #define PATH_MAX 4096 18 | #endif 19 | 20 | #ifndef SO_REUSEPORT 21 | #define SO_REUSEPORT 15 22 | #endif 23 | 24 | #ifndef TCP_FASTOPEN 25 | #define TCP_FASTOPEN 23 26 | #endif 27 | 28 | #ifndef MSG_FASTOPEN 29 | #define MSG_FASTOPEN 0x20000000 30 | #endif 31 | 32 | #ifndef IP_TRANSPARENT 33 | #define IP_TRANSPARENT 19 34 | #endif 35 | 36 | #ifndef IPV6_TRANSPARENT 37 | #define IPV6_TRANSPARENT 75 38 | #endif 39 | 40 | #ifndef IP_RECVORIGDSTADDR 41 | #define IP_RECVORIGDSTADDR 20 42 | #endif 43 | 44 | #ifndef IPV6_RECVORIGDSTADDR 45 | #define IPV6_RECVORIGDSTADDR 74 46 | #endif 47 | 48 | #ifndef SO_ORIGINAL_DST 49 | #define SO_ORIGINAL_DST 80 50 | #endif 51 | 52 | #ifndef IP6T_SO_ORIGINAL_DST 53 | #define IP6T_SO_ORIGINAL_DST 80 54 | #endif 55 | 56 | void set_nofile_limit(size_t nofile) { 57 | if (setrlimit(RLIMIT_NOFILE, &(struct rlimit){nofile, nofile}) < 0) { 58 | LOGERR("[set_nofile_limit] setrlimit(nofile, %zu): %s", nofile, strerror(errno)); 59 | } 60 | } 61 | 62 | size_t get_nofile_limit(void) { 63 | struct rlimit v; 64 | if (getrlimit(RLIMIT_NOFILE, &v) < 0) { 65 | LOGERR("[get_nofile_limit] getrlimit(nofile): %s", strerror(errno)); 66 | v.rlim_cur = 0; 67 | } 68 | return v.rlim_cur; 69 | } 70 | 71 | /* declare function prototype (openwrt?) */ 72 | int initgroups(const char *user, gid_t group); 73 | 74 | void run_as_user(const char *username, char *argv[]) { 75 | if (geteuid() != 0) return; /* ignore if current user is not root */ 76 | 77 | const struct passwd *userinfo = getpwnam(username); 78 | if (!userinfo) { 79 | LOGERR("[run_as_user] user:'%s' does not exist in this system", username); 80 | return; 81 | } 82 | 83 | if (userinfo->pw_uid == 0) return; /* ignore if target user is root */ 84 | 85 | if (setgid(userinfo->pw_gid) < 0) { 86 | LOGERR("[run_as_user] change to gid:%u of user:'%s': %s", userinfo->pw_gid, userinfo->pw_name, strerror(errno)); 87 | exit(errno); 88 | } 89 | 90 | if (initgroups(userinfo->pw_name, userinfo->pw_gid) < 0) { 91 | LOGERR("[run_as_user] initgroups(%u) of user:'%s': %s", userinfo->pw_gid, userinfo->pw_name, strerror(errno)); 92 | exit(errno); 93 | } 94 | 95 | if (setuid(userinfo->pw_uid) < 0) { 96 | LOGERR("[run_as_user] change to uid:%u of user:'%s': %s", userinfo->pw_uid, userinfo->pw_name, strerror(errno)); 97 | exit(errno); 98 | } 99 | 100 | static char execfile_abspath[PATH_MAX] = {0}; 101 | if (readlink("/proc/self/exe", execfile_abspath, PATH_MAX - 1) < 0) { 102 | LOGERR("[run_as_user] readlink('/proc/self/exe'): %s", strerror(errno)); 103 | exit(errno); 104 | } 105 | 106 | if (execv(execfile_abspath, argv) < 0) { 107 | LOGERR("[run_as_user] execv('%s', args): %s", execfile_abspath, strerror(errno)); 108 | exit(errno); 109 | } 110 | } 111 | 112 | int get_ipstr_family(const char *ipstr) { 113 | if (!ipstr) return -1; /* invalid */ 114 | ipaddr6_t ipaddr; /* save output */ 115 | if (inet_pton(AF_INET, ipstr, &ipaddr) == 1) { 116 | return AF_INET; 117 | } else if (inet_pton(AF_INET6, ipstr, &ipaddr) == 1) { 118 | return AF_INET6; 119 | } else { 120 | return -1; /* invalid */ 121 | } 122 | } 123 | 124 | void build_socket_addr(int family, void *skaddr, const char *ipstr, portno_t portno) { 125 | if (family == AF_INET) { 126 | skaddr4_t *addr = skaddr; 127 | addr->sin_family = AF_INET; 128 | inet_pton(AF_INET, ipstr, &addr->sin_addr); 129 | addr->sin_port = htons(portno); 130 | } else { 131 | skaddr6_t *addr = skaddr; 132 | addr->sin6_family = AF_INET6; 133 | inet_pton(AF_INET6, ipstr, &addr->sin6_addr); 134 | addr->sin6_port = htons(portno); 135 | } 136 | } 137 | 138 | void parse_socket_addr(const void *skaddr, char *ipstr, portno_t *portno) { 139 | if (((const skaddr4_t *)skaddr)->sin_family == AF_INET) { 140 | const skaddr4_t *addr = skaddr; 141 | inet_ntop(AF_INET, &addr->sin_addr, ipstr, IP4STRLEN); 142 | *portno = ntohs(addr->sin_port); 143 | } else { 144 | const skaddr6_t *addr = skaddr; 145 | inet_ntop(AF_INET6, &addr->sin6_addr, ipstr, IP6STRLEN); 146 | *portno = ntohs(addr->sin6_port); 147 | } 148 | } 149 | 150 | static inline void set_non_block(int sockfd) { 151 | int flags = fcntl(sockfd, F_GETFL, 0); 152 | if (flags < 0) { 153 | LOGERR("[set_non_block] fcntl(%d, F_GETFL): %s", sockfd, strerror(errno)); 154 | return; 155 | } 156 | if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) < 0) { 157 | LOGERR("[set_non_block] fcntl(%d, F_SETFL): %s", sockfd, strerror(errno)); 158 | return; 159 | } 160 | } 161 | 162 | static inline void set_ipv6_only(int sockfd) { 163 | if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){1}, sizeof(int)) < 0) { 164 | LOGERR("[set_ipv6_only] setsockopt(%d, IPV6_V6ONLY): %s", sockfd, strerror(errno)); 165 | } 166 | } 167 | 168 | static inline void set_reuse_addr(int sockfd) { 169 | if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0) { 170 | LOGERR("[set_reuse_addr] setsockopt(%d, SO_REUSEADDR): %s", sockfd, strerror(errno)); 171 | } 172 | } 173 | 174 | static inline void set_reuse_port(int sockfd) { 175 | if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &(int){1}, sizeof(int)) < 0) { 176 | LOGERR("[set_reuse_port] setsockopt(%d, SO_REUSEPORT): %s", sockfd, strerror(errno)); 177 | } 178 | } 179 | 180 | static inline void set_tfo_accept(int sockfd) { 181 | if (setsockopt(sockfd, IPPROTO_TCP, TCP_FASTOPEN, &(int){5}, sizeof(int)) < 0) { 182 | LOGERR("[set_tfo_accept] setsockopt(%d, TCP_FASTOPEN): %s", sockfd, strerror(errno)); 183 | } 184 | } 185 | 186 | static inline void set_tcp_syncnt(int sockfd, int syncnt) { 187 | if (setsockopt(sockfd, IPPROTO_TCP, TCP_SYNCNT, &syncnt, sizeof(int)) < 0) { 188 | LOGERR("[set_tcp_syncnt] setsockopt(%d, TCP_SYNCNT): %s", sockfd, strerror(errno)); 189 | } 190 | } 191 | 192 | static inline void set_tcp_nodelay(int sockfd) { 193 | if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &(int){1}, sizeof(int)) < 0) { 194 | LOGERR("[set_tcp_nodelay] setsockopt(%d, TCP_NODELAY): %s", sockfd, strerror(errno)); 195 | } 196 | } 197 | 198 | static inline void set_tcp_quickack(int sockfd) { 199 | if (setsockopt(sockfd, IPPROTO_TCP, TCP_QUICKACK, &(int){1}, sizeof(int)) < 0) { 200 | LOGERR("[set_tcp_quickack] setsockopt(%d, TCP_QUICKACK): %s", sockfd, strerror(errno)); 201 | } 202 | } 203 | 204 | static inline void set_tcp_solinger0(int sockfd) { 205 | if (setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &(struct linger){.l_onoff = 1, .l_linger = 0}, sizeof(struct linger)) < 0) { 206 | LOGERR("[set_tcp_solinger0] setsockopt(%d, SO_LINGER): %s", sockfd, strerror(errno)); 207 | } 208 | } 209 | 210 | static inline void set_tcp_keepalive(int sockfd) { 211 | /* enable tcp_keepalive */ 212 | if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &(int){1}, sizeof(int)) < 0) { 213 | LOGERR("[set_tcp_keepalive] setsockopt(%d, SO_KEEPALIVE): %s", sockfd, strerror(errno)); 214 | return; 215 | } 216 | /* tcp connection idle sec */ 217 | if (setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, &(int){60}, sizeof(int)) < 0) { 218 | LOGERR("[set_tcp_keepalive] setsockopt(%d, TCP_KEEPIDLE): %s", sockfd, strerror(errno)); 219 | return; 220 | } 221 | /* keepalive probe retry max count */ 222 | if (setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT, &(int){3}, sizeof(int)) < 0) { 223 | LOGERR("[set_tcp_keepalive] setsockopt(%d, TCP_KEEPCNT): %s", sockfd, strerror(errno)); 224 | return; 225 | } 226 | /* keepalive probe retry interval sec */ 227 | if (setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL, &(int){5}, sizeof(int)) < 0) { 228 | LOGERR("[set_tcp_keepalive] setsockopt(%d, TCP_KEEPINTVL): %s", sockfd, strerror(errno)); 229 | return; 230 | } 231 | } 232 | 233 | static inline void set_ip_transparent(int family, int sockfd) { 234 | if (family == AF_INET) { 235 | if (setsockopt(sockfd, IPPROTO_IP, IP_TRANSPARENT, &(int){1}, sizeof(int)) < 0) { 236 | LOGERR("[set_ip_transparent] setsockopt(%d, IP_TRANSPARENT): %s", sockfd, strerror(errno)); 237 | return; 238 | } 239 | } else { 240 | if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_TRANSPARENT, &(int){1}, sizeof(int)) < 0) { 241 | LOGERR("[set_ip_transparent] setsockopt(%d, IPV6_TRANSPARENT): %s", sockfd, strerror(errno)); 242 | return; 243 | } 244 | } 245 | } 246 | 247 | static inline void set_recv_origdstaddr(int family, int sockfd) { 248 | if (family == AF_INET) { 249 | if (setsockopt(sockfd, IPPROTO_IP, IP_RECVORIGDSTADDR, &(int){1}, sizeof(int)) < 0) { 250 | LOGERR("[set_recv_origdstaddr] setsockopt(%d, IP_RECVORIGDSTADDR): %s", sockfd, strerror(errno)); 251 | return; 252 | } 253 | } else { 254 | if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVORIGDSTADDR, &(int){1}, sizeof(int)) < 0) { 255 | LOGERR("[set_recv_origdstaddr] setsockopt(%d, IPV6_RECVORIGDSTADDR): %s", sockfd, strerror(errno)); 256 | return; 257 | } 258 | } 259 | } 260 | 261 | static inline void setup_accepted_sockfd(int sockfd) { 262 | set_non_block(sockfd); 263 | set_tcp_nodelay(sockfd); 264 | set_tcp_quickack(sockfd); 265 | set_tcp_keepalive(sockfd); 266 | } 267 | 268 | void new_nonblock_pipefd(int pipefd[2]) { 269 | if (pipe(pipefd) < 0) { 270 | LOGERR("[new_nonblock_pipefd] pipe(%p): %s", (void *)pipefd, strerror(errno)); 271 | pipefd[0] = pipefd[1] = -1; 272 | return; 273 | } 274 | set_non_block(pipefd[0]); 275 | set_non_block(pipefd[1]); 276 | } 277 | 278 | static inline int new_nonblock_sockfd(int family, int sktype) { 279 | int sockfd = socket(family, sktype, 0); 280 | if (sockfd < 0) { 281 | LOGERR("[new_nonblock_sockfd] socket(%s, %s): %s", family == AF_INET ? "AF_INET" : "AF_INET6", sktype == SOCK_STREAM ? "SOCK_STREAM" : "SOCK_DGRAM", strerror(errno)); 282 | return -1; 283 | } 284 | set_non_block(sockfd); 285 | if (family == AF_INET6) set_ipv6_only(sockfd); 286 | set_reuse_addr(sockfd); 287 | return sockfd; 288 | } 289 | 290 | int new_tcp_listen_sockfd(int family, bool is_tproxy, bool is_reuse_port, bool is_tfo_accept) { 291 | int sockfd = new_nonblock_sockfd(family, SOCK_STREAM); 292 | if (is_tproxy) set_ip_transparent(family, sockfd); 293 | if (is_reuse_port) set_reuse_port(sockfd); 294 | if (is_tfo_accept) set_tfo_accept(sockfd); 295 | return sockfd; 296 | } 297 | 298 | int new_tcp_connect_sockfd(int family, uint8_t tcp_syncnt) { 299 | int sockfd = new_nonblock_sockfd(family, SOCK_STREAM); 300 | set_tcp_nodelay(sockfd); 301 | set_tcp_quickack(sockfd); 302 | set_tcp_keepalive(sockfd); 303 | if (tcp_syncnt) set_tcp_syncnt(sockfd, tcp_syncnt); 304 | return sockfd; 305 | } 306 | 307 | int new_udp_tprecv_sockfd(int family) { 308 | int sockfd = new_nonblock_sockfd(family, SOCK_DGRAM); 309 | set_ip_transparent(family, sockfd); 310 | set_recv_origdstaddr(family, sockfd); 311 | return sockfd; 312 | } 313 | 314 | int new_udp_tpsend_sockfd(int family) { 315 | int sockfd = new_nonblock_sockfd(family, SOCK_DGRAM); 316 | set_ip_transparent(family, sockfd); 317 | return sockfd; 318 | } 319 | 320 | int new_udp_normal_sockfd(int family) { 321 | return new_nonblock_sockfd(family, SOCK_DGRAM); 322 | } 323 | 324 | bool get_tcp_orig_dstaddr(int family, int sockfd, void *dstaddr, bool is_tproxy) { 325 | socklen_t addrlen = (family == AF_INET) ? sizeof(skaddr4_t) : sizeof(skaddr6_t); 326 | if (is_tproxy) { 327 | if (getsockname(sockfd, dstaddr, &addrlen) < 0) { 328 | LOGERR("[get_tcp_orig_dstaddr] addr_family:%s, getsockname(%d): %s", (family == AF_INET) ? "inet" : "inet6", sockfd, strerror(errno)); 329 | return false; 330 | } 331 | } else { 332 | if (family == AF_INET) { 333 | if (getsockopt(sockfd, IPPROTO_IP, SO_ORIGINAL_DST, dstaddr, &addrlen) < 0) { 334 | LOGERR("[get_tcp_orig_dstaddr] getsockopt(%d, SO_ORIGINAL_DST): %s", sockfd, strerror(errno)); 335 | return false; 336 | } 337 | } else { 338 | if (getsockopt(sockfd, IPPROTO_IPV6, IP6T_SO_ORIGINAL_DST, dstaddr, &addrlen) < 0) { 339 | LOGERR("[get_tcp_orig_dstaddr] getsockopt(%d, IP6T_SO_ORIGINAL_DST): %s", sockfd, strerror(errno)); 340 | return false; 341 | } 342 | } 343 | } 344 | return true; 345 | } 346 | 347 | #pragma GCC diagnostic push 348 | #pragma GCC diagnostic ignored "-Wsign-compare" /* CMSG_NXTHDR */ 349 | bool get_udp_orig_dstaddr(int family, struct msghdr *msg, void *dstaddr) { 350 | if (family == AF_INET) { 351 | for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { 352 | if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVORIGDSTADDR) { 353 | memcpy(dstaddr, CMSG_DATA(cmsg), sizeof(skaddr4_t)); 354 | return true; 355 | } 356 | } 357 | } else { 358 | for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { 359 | if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_RECVORIGDSTADDR) { 360 | memcpy(dstaddr, CMSG_DATA(cmsg), sizeof(skaddr6_t)); 361 | return true; 362 | } 363 | } 364 | } 365 | return false; 366 | } 367 | #pragma GCC diagnostic pop 368 | 369 | /* same as `accept()`, just a simple wrapper */ 370 | int tcp_accept(int sockfd, void *addr, socklen_t *addrlen) { 371 | int newsockfd = accept(sockfd, addr, addrlen); 372 | if (newsockfd >= 0) setup_accepted_sockfd(newsockfd); 373 | return newsockfd; 374 | } 375 | 376 | /* return: is_succ, tfo_succ if tfo_nsend >= 0 */ 377 | bool tcp_connect(int sockfd, const void *addr, const void *tfo_data, size_t tfo_datalen, ssize_t *tfo_nsend) { 378 | socklen_t addrlen = ((skaddr4_t *)addr)->sin_family == AF_INET ? sizeof(skaddr4_t) : sizeof(skaddr6_t); 379 | if (tfo_data && tfo_datalen && tfo_nsend) { 380 | if ((*tfo_nsend = sendto(sockfd, tfo_data, tfo_datalen, MSG_FASTOPEN, addr, addrlen)) < 0 && errno != EINPROGRESS) return false; 381 | } else { 382 | if (connect(sockfd, addr, addrlen) < 0 && errno != EINPROGRESS) return false; 383 | } 384 | return true; 385 | } 386 | 387 | /* on connect error, errno is set appropriately */ 388 | bool tcp_has_error(int sockfd) { 389 | return getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &errno, &(socklen_t){sizeof(errno)}) < 0 || errno; 390 | } 391 | 392 | /* set so_linger(delay=0) and call close(sockfd) */ 393 | void tcp_close_by_rst(int sockfd) { 394 | set_tcp_solinger0(sockfd); 395 | close(sockfd); 396 | } 397 | -------------------------------------------------------------------------------- /src/netutils.h: -------------------------------------------------------------------------------- 1 | #ifndef IPT2SOCKS_NETUTILS_H 2 | #define IPT2SOCKS_NETUTILS_H 3 | 4 | #define _GNU_SOURCE 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define IP4BINLEN 4 12 | #define IP6BINLEN 16 13 | 14 | #define IP4STRLEN INET_ADDRSTRLEN 15 | #define IP6STRLEN INET6_ADDRSTRLEN 16 | #define PORTSTRLEN 6 17 | 18 | #define IP4STR_LOOPBACK "127.0.0.1" 19 | #define IP4STR_WILDCARD "0.0.0.0" 20 | #define IP6STR_LOOPBACK "::1" 21 | #define IP6STR_WILDCARD "::" 22 | 23 | #define UDP_CTRLMESG_BUFSIZ 64 24 | #define UDP_DATAGRAM_MAXSIZ 65507 /* 65535 - iphdr(20) - udphdr(8) */ 25 | 26 | typedef uint32_t ipaddr4_t; 27 | typedef uint8_t ipaddr6_t[16]; 28 | 29 | typedef union { 30 | ipaddr4_t ip4; 31 | ipaddr6_t ip6; 32 | } ipaddr_t; 33 | 34 | typedef uint16_t portno_t; 35 | 36 | typedef struct { 37 | ipaddr_t ip; 38 | portno_t port; 39 | } ip_port_t; 40 | 41 | typedef struct sockaddr_in skaddr4_t; 42 | typedef struct sockaddr_in6 skaddr6_t; 43 | 44 | void set_nofile_limit(size_t nofile); 45 | size_t get_nofile_limit(void); 46 | 47 | void run_as_user(const char *username, char *argv[]); 48 | 49 | int get_ipstr_family(const char *ipstr); 50 | void build_socket_addr(int family, void *skaddr, const char *ipstr, portno_t portno); 51 | void parse_socket_addr(const void *skaddr, char *ipstr, portno_t *portno); 52 | 53 | void new_nonblock_pipefd(int pipefd[2]); /* pipefd[0]: read end, pipefd[1]: write end */ 54 | 55 | int new_tcp_listen_sockfd(int family, bool is_tproxy, bool is_reuse_port, bool is_tfo_accept); 56 | int new_tcp_connect_sockfd(int family, uint8_t tcp_syncnt); 57 | 58 | int new_udp_tprecv_sockfd(int family); 59 | int new_udp_tpsend_sockfd(int family); 60 | int new_udp_normal_sockfd(int family); 61 | 62 | bool get_tcp_orig_dstaddr(int family, int sockfd, void *dstaddr, bool is_tproxy); 63 | bool get_udp_orig_dstaddr(int family, struct msghdr *msg, void *dstaddr); 64 | 65 | /* same as `accept()`, just a simple wrapper */ 66 | int tcp_accept(int sockfd, void *addr, socklen_t *addrlen); 67 | 68 | /* return: is_succ, tfo_succ if tfo_nsend >= 0 */ 69 | bool tcp_connect(int sockfd, const void *addr, const void *tfo_data, size_t tfo_datalen, ssize_t *tfo_nsend); 70 | 71 | /* on connect error, errno is set appropriately */ 72 | bool tcp_has_error(int sockfd); 73 | 74 | /* set so_linger(delay=0) and call close(sockfd) */ 75 | void tcp_close_by_rst(int sockfd); 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /src/protocol.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include "protocol.h" 3 | #include "logutils.h" 4 | #include 5 | #include 6 | #include 7 | 8 | socks5_authreq_t g_socks5_auth_request = { 9 | .version = SOCKS5_VERSION, 10 | .mlength = 1, 11 | .method = SOCKS5_METHOD_NOAUTH, /* noauth by default */ 12 | }; 13 | 14 | char g_socks5_usrpwd_request[SOCKS5_USRPWD_REQMAXLEN] = {0}; 15 | uint16_t g_socks5_usrpwd_requestlen = 0; 16 | 17 | const socks5_ipv4req_t G_SOCKS5_UDP4_REQUEST = { 18 | .version = SOCKS5_VERSION, 19 | .command = SOCKS5_COMMAND_UDPASSOCIATE, 20 | .reserved = 0, 21 | .addrtype = SOCKS5_ADDRTYPE_IPV4, 22 | .ipaddr4 = 0, 23 | .portnum = 0, 24 | }; 25 | 26 | const socks5_ipv6req_t G_SOCKS5_UDP6_REQUEST = { 27 | .version = SOCKS5_VERSION, 28 | .command = SOCKS5_COMMAND_UDPASSOCIATE, 29 | .reserved = 0, 30 | .addrtype = SOCKS5_ADDRTYPE_IPV6, 31 | .ipaddr6 = {0}, 32 | .portnum = 0, 33 | }; 34 | 35 | void socks5_usrpwd_request_make(const char *username, const char *password) { 36 | g_socks5_auth_request.method = SOCKS5_METHOD_USRPWD; 37 | 38 | socks5_usrpwdreq_t *usrpwdreq = (void *)g_socks5_usrpwd_request; 39 | usrpwdreq->version = SOCKS5_USRPWD_VERSION; 40 | 41 | uint8_t *usrlenptr = (void *)usrpwdreq + 1; 42 | *usrlenptr = strlen(username); 43 | 44 | char *usrbufptr = (void *)usrlenptr + 1; 45 | memcpy(usrbufptr, username, *usrlenptr); 46 | 47 | uint8_t *pwdlenptr = (void *)usrbufptr + *usrlenptr; 48 | *pwdlenptr = strlen(password); 49 | 50 | char *pwdbufptr = (void *)pwdlenptr + 1; 51 | memcpy(pwdbufptr, password, *pwdlenptr); 52 | 53 | g_socks5_usrpwd_requestlen = 1 + 1 + *usrlenptr + 1 + *pwdlenptr; 54 | } 55 | 56 | void socks5_proxy_request_make(socks5_ipv4req_t *request, const void *skaddr) { 57 | request->version = SOCKS5_VERSION; 58 | request->command = SOCKS5_COMMAND_CONNECT; 59 | request->reserved = 0; 60 | if (((skaddr4_t *)skaddr)->sin_family == AF_INET) { 61 | const skaddr4_t *addr = skaddr; 62 | request->addrtype = SOCKS5_ADDRTYPE_IPV4; 63 | request->ipaddr4 = addr->sin_addr.s_addr; 64 | request->portnum = addr->sin_port; 65 | } else { 66 | const skaddr6_t *addr = skaddr; 67 | socks5_ipv6req_t *req = (socks5_ipv6req_t *)request; 68 | req->addrtype = SOCKS5_ADDRTYPE_IPV6; 69 | memcpy(&req->ipaddr6, &addr->sin6_addr.s6_addr, IP6BINLEN); 70 | req->portnum = addr->sin6_port; 71 | } 72 | } 73 | 74 | static inline const char* socks5_rcode2string(uint8_t rcode) { 75 | switch (rcode) { 76 | case SOCKS5_RESPCODE_SUCCEEDED: return "Succeeded"; 77 | case SOCKS5_RESPCODE_SVRGENERR: return "General server failure"; 78 | case SOCKS5_RESPCODE_NOTALLOWED: return "Not allowed by ruleset"; 79 | case SOCKS5_RESPCODE_NETUNREACH: return "Network unreachable"; 80 | case SOCKS5_RESPCODE_HOSTUNREACH: return "Host unreachable"; 81 | case SOCKS5_RESPCODE_CONNREFUSED: return "Connection refused"; 82 | case SOCKS5_RESPCODE_TTLEXPIRED: return "TTL expired"; 83 | case SOCKS5_RESPCODE_COMMANDNOTSPT: return "Command not supported"; 84 | case SOCKS5_RESPCODE_ADDRTYPENOTSPT: return "Address type not supported"; 85 | } 86 | return "Unknown response code"; 87 | } 88 | 89 | bool socks5_auth_response_check(const char *funcname, const socks5_authresp_t *response) { 90 | if (response->version != SOCKS5_VERSION) { 91 | LOGERR("[%s] response.version:%#hhx != %#x", funcname, response->version, SOCKS5_VERSION); 92 | return false; 93 | } 94 | if (response->method != g_socks5_auth_request.method) { 95 | LOGERR("[%s] response.method:%#hhx != %s", funcname, response->method, g_socks5_usrpwd_requestlen ? "USRPWD" : "NOAUTH"); 96 | return false; 97 | } 98 | return true; 99 | } 100 | 101 | bool socks5_usrpwd_response_check(const char *funcname, const socks5_usrpwdresp_t *response) { 102 | if (response->version != SOCKS5_USRPWD_VERSION) { 103 | LOGERR("[%s] response.version:%#hhx != %#x", funcname, response->version, SOCKS5_USRPWD_VERSION); 104 | return false; 105 | } 106 | if (response->respcode != SOCKS5_USRPWD_AUTHSUCC) { 107 | LOGERR("[%s] response.respcode:%#hhx != AUTHSUCC", funcname, response->respcode); 108 | return false; 109 | } 110 | return true; 111 | } 112 | 113 | bool socks5_proxy_response_check(const char *funcname, const socks5_ipv4resp_t *response) { 114 | if (response->version != SOCKS5_VERSION) { 115 | LOGERR("[%s] response.version:%#hhx != %#x", funcname, response->version, SOCKS5_VERSION); 116 | return false; 117 | } 118 | if (response->respcode != SOCKS5_RESPCODE_SUCCEEDED) { 119 | LOGERR("[%s] response.respcode:%#hhx(%s) != SUCCEEDED", funcname, response->respcode, socks5_rcode2string(response->respcode)); 120 | return false; 121 | } 122 | return true; 123 | } 124 | -------------------------------------------------------------------------------- /src/protocol.h: -------------------------------------------------------------------------------- 1 | #ifndef IPT2SOCKS_PROTOCOL_H 2 | #define IPT2SOCKS_PROTOCOL_H 3 | 4 | #define _GNU_SOURCE 5 | #include "netutils.h" 6 | 7 | /* socks5 protocol version number */ 8 | #define SOCKS5_VERSION 0x05 9 | 10 | /* method code constant definition */ 11 | #define SOCKS5_METHOD_NOAUTH 0x00 12 | #define SOCKS5_METHOD_USRPWD 0x02 13 | 14 | /* usrpwd-auth constant definition */ 15 | #define SOCKS5_USRPWD_VERSION 0x01 16 | #define SOCKS5_USRPWD_AUTHSUCC 0x00 17 | #define SOCKS5_USRPWD_USRMAXLEN 255 18 | #define SOCKS5_USRPWD_PWDMAXLEN 255 19 | #define SOCKS5_USRPWD_REQMAXLEN (1 + 1 + SOCKS5_USRPWD_USRMAXLEN + 1 + SOCKS5_USRPWD_PWDMAXLEN) 20 | 21 | /* command type constant definition */ 22 | #define SOCKS5_COMMAND_CONNECT 0x01 23 | #define SOCKS5_COMMAND_UDPASSOCIATE 0x03 24 | 25 | /* address type constant definition */ 26 | #define SOCKS5_ADDRTYPE_IPV4 0x01 27 | #define SOCKS5_ADDRTYPE_IPV6 0x04 28 | 29 | /* response code constant definition */ 30 | #define SOCKS5_RESPCODE_SUCCEEDED 0x00 31 | #define SOCKS5_RESPCODE_SVRGENERR 0x01 32 | #define SOCKS5_RESPCODE_NOTALLOWED 0x02 33 | #define SOCKS5_RESPCODE_NETUNREACH 0x03 34 | #define SOCKS5_RESPCODE_HOSTUNREACH 0x04 35 | #define SOCKS5_RESPCODE_CONNREFUSED 0x05 36 | #define SOCKS5_RESPCODE_TTLEXPIRED 0x06 37 | #define SOCKS5_RESPCODE_COMMANDNOTSPT 0x07 38 | #define SOCKS5_RESPCODE_ADDRTYPENOTSPT 0x08 39 | #define SOCKS5_RESPCODE_09FFUNASSIGNED 0x09 40 | 41 | /* socks5 authentication request */ 42 | typedef struct { 43 | uint8_t version; /* 0x05 */ 44 | uint8_t mlength; /* 0x01 */ 45 | uint8_t method; /* 0x00 */ 46 | } __attribute__((packed)) socks5_authreq_t; 47 | 48 | /* socks5 authentication response */ 49 | typedef struct { 50 | uint8_t version; /* 0x05 */ 51 | uint8_t method; /* 0x00 */ 52 | } __attribute__((packed)) socks5_authresp_t; 53 | 54 | /* socks5 username-password request */ 55 | typedef struct { 56 | uint8_t version; /* 0x01 */ 57 | // USERNAME_LEN, sizeof=1, range=1~255 58 | // USERNAME_STR, sizeof=1~255, without '\0' 59 | // PASSWORD_LEN, sizeof=1, range=1~255 60 | // PASSWORD_STR, sizeof=1~255, without '\0' 61 | } __attribute__((packed)) socks5_usrpwdreq_t; 62 | 63 | /* socks5 username-password response */ 64 | typedef struct { 65 | uint8_t version; /* 0x01 */ 66 | uint8_t respcode; /* 0x00=SUCC, other=FAIL */ 67 | } __attribute__((packed)) socks5_usrpwdresp_t; 68 | 69 | /* socks5 ipv4-proxy request */ 70 | typedef struct { 71 | uint8_t version; 72 | uint8_t command; 73 | uint8_t reserved; /* 0x00 */ 74 | uint8_t addrtype; 75 | ipaddr4_t ipaddr4; 76 | portno_t portnum; 77 | } __attribute__((packed)) socks5_ipv4req_t; 78 | 79 | /* socks5 ipv6-proxy request */ 80 | typedef struct { 81 | uint8_t version; 82 | uint8_t command; 83 | uint8_t reserved; /* 0x00 */ 84 | uint8_t addrtype; 85 | ipaddr6_t ipaddr6; 86 | portno_t portnum; 87 | } __attribute__((packed)) socks5_ipv6req_t; 88 | 89 | /* socks5 ipv4-proxy response */ 90 | typedef struct { 91 | uint8_t version; 92 | uint8_t respcode; 93 | uint8_t reserved; /* 0x00 */ 94 | uint8_t addrtype; 95 | ipaddr4_t ipaddr4; 96 | portno_t portnum; 97 | } __attribute__((packed)) socks5_ipv4resp_t; 98 | 99 | /* socks5 ipv6-proxy response */ 100 | typedef struct { 101 | uint8_t version; 102 | uint8_t respcode; 103 | uint8_t reserved; /* 0x00 */ 104 | uint8_t addrtype; 105 | ipaddr6_t ipaddr6; 106 | portno_t portnum; 107 | } __attribute__((packed)) socks5_ipv6resp_t; 108 | 109 | /* socks5 ipv4-udp message header */ 110 | typedef struct { 111 | uint16_t reserved; /* 0x0000 */ 112 | uint8_t fragment; /* 0x00 */ 113 | uint8_t addrtype; 114 | ipaddr4_t ipaddr4; 115 | portno_t portnum; 116 | uint8_t payload[]; /* sizeof = 0 */ 117 | } __attribute__((packed)) socks5_udp4msg_t; 118 | 119 | /* socks5 ipv6-udp message header */ 120 | typedef struct { 121 | uint16_t reserved; /* 0x0000 */ 122 | uint8_t fragment; /* 0x00 */ 123 | uint8_t addrtype; 124 | ipaddr6_t ipaddr6; 125 | portno_t portnum; 126 | uint8_t payload[]; /* sizeof = 0 */ 127 | } __attribute__((packed)) socks5_udp6msg_t; 128 | 129 | extern socks5_authreq_t g_socks5_auth_request; 130 | 131 | extern char g_socks5_usrpwd_request[]; 132 | extern uint16_t g_socks5_usrpwd_requestlen; 133 | 134 | extern const socks5_ipv4req_t G_SOCKS5_UDP4_REQUEST; 135 | extern const socks5_ipv6req_t G_SOCKS5_UDP6_REQUEST; 136 | 137 | void socks5_usrpwd_request_make(const char *username, const char *password); 138 | void socks5_proxy_request_make(socks5_ipv4req_t *request, const void *skaddr); 139 | 140 | bool socks5_auth_response_check(const char *funcname, const socks5_authresp_t *response); 141 | bool socks5_usrpwd_response_check(const char *funcname, const socks5_usrpwdresp_t *response); 142 | bool socks5_proxy_response_check(const char *funcname, const socks5_ipv4resp_t *response); 143 | 144 | #endif 145 | --------------------------------------------------------------------------------