├── .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 |
--------------------------------------------------------------------------------