From 52b7373fe39115895f91fef0221fcc0ec5b7c9a0 Mon Sep 17 00:00:00 2001 From: alterdekim Date: Sun, 8 Dec 2024 01:44:13 +0300 Subject: [PATCH] Rebuilding the whole world! modified: Cargo.toml new file: LICENSE.md renamed: Cargo.lock -> frida_core/Cargo.lock new file: frida_core/Cargo.toml renamed: build.rs -> frida_core/build.rs renamed: icons/off.ico -> frida_core/icons/off.ico renamed: icons/on.ico -> frida_core/icons/on.ico renamed: src/android.rs -> frida_core/src/android.rs renamed: src/client.rs -> frida_core/src/client.rs renamed: src/config/mod.rs -> frida_core/src/config/mod.rs renamed: src/gui/mod.rs -> frida_core/src/gui/mod.rs renamed: src/gui/tab/mod.rs -> frida_core/src/gui/tab/mod.rs renamed: src/gui/tab_button.rs -> frida_core/src/gui/tab_button.rs renamed: src/gui/tab_panel.rs -> frida_core/src/gui/tab_panel.rs renamed: src/main.rs -> frida_core/src/main.rs renamed: src/obfs.rs -> frida_core/src/obfs.rs renamed: src/server.rs -> frida_core/src/server.rs renamed: src/udp.rs -> frida_core/src/udp.rs renamed: tray.rc -> frida_core/tray.rc --- Cargo.toml | 64 +- LICENSE.md | 661 +++++++++++++++++++ Cargo.lock => frida_core/Cargo.lock | 0 frida_core/Cargo.toml | 60 ++ build.rs => frida_core/build.rs | 0 {icons => frida_core/icons}/off.ico | Bin {icons => frida_core/icons}/on.ico | Bin {src => frida_core/src}/android.rs | 0 {src => frida_core/src}/client.rs | 762 +++++++++++----------- {src => frida_core/src}/config/mod.rs | 0 {src => frida_core/src}/gui/mod.rs | 0 {src => frida_core/src}/gui/tab/mod.rs | 0 {src => frida_core/src}/gui/tab_button.rs | 0 {src => frida_core/src}/gui/tab_panel.rs | 0 {src => frida_core/src}/main.rs | 340 +++++----- {src => frida_core/src}/obfs.rs | 0 {src => frida_core/src}/server.rs | 500 +++++++------- {src => frida_core/src}/udp.rs | 0 tray.rc => frida_core/tray.rc | 0 19 files changed, 1529 insertions(+), 858 deletions(-) create mode 100644 LICENSE.md rename Cargo.lock => frida_core/Cargo.lock (100%) create mode 100644 frida_core/Cargo.toml rename build.rs => frida_core/build.rs (100%) rename {icons => frida_core/icons}/off.ico (100%) rename {icons => frida_core/icons}/on.ico (100%) rename {src => frida_core/src}/android.rs (100%) rename {src => frida_core/src}/client.rs (97%) rename {src => frida_core/src}/config/mod.rs (100%) rename {src => frida_core/src}/gui/mod.rs (100%) rename {src => frida_core/src}/gui/tab/mod.rs (100%) rename {src => frida_core/src}/gui/tab_button.rs (100%) rename {src => frida_core/src}/gui/tab_panel.rs (100%) rename {src => frida_core/src}/main.rs (97%) rename {src => frida_core/src}/obfs.rs (100%) rename {src => frida_core/src}/server.rs (97%) rename {src => frida_core/src}/udp.rs (100%) rename tray.rc => frida_core/tray.rc (100%) diff --git a/Cargo.toml b/Cargo.toml index 7b419e6..b47db8b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,62 +1,12 @@ +[workspace] +members = ["frida_core","frida_client","frida_server","frida_cli","frida_gui","frida_lib"] + [package] name = "frida_vpn" -version = "0.1.7" +version = "0.2.0" edition = "2021" -license = "Apache-2.0" -authors = ["alterdekim"] +license-file = "LICENSE.md" +authors = ["alterwain"] keywords = ["tun", "network", "tunnel", "vpn"] categories = ["network-programming", "asynchronous"] -readme = "README.md" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[lib] -crate-type = ["cdylib"] -path = "src/android.rs" - -[[bin]] -name = "frida-cli" -path = "src/main.rs" - -[[bin]] -name = "frida-gui" -path = "src/gui/mod.rs" - -[dependencies] -clap = "2.33" -aes-gcm = "0.10.3" -tokio = { version = "1", features = ["full", "signal", "tracing"] } -tokio-util = "0.7.12" -serde = "1.0" -serde_derive = "1.0.190" -rand = { version = "0.8.5", features = ["small_rng", "getrandom", "std_rng"] } -block-modes = "0.8" -block-padding = "0.2" -generic-array = "0.14" -env_logger = "0.9" -log = "0.4.20" -futures = "0.3.30" -packet = "0.1.4" -async-channel = "2.3.1" -hex = "0.4" -serde_yaml = "0.9.34" -x25519-dalek = { version = "2.0.1", features = ["getrandom", "static_secrets"] } -base64 = "0.22.1" -chrono = "0.4.38" -console-subscriber = "0.4.0" -network-interface = "2.0.0" -tun = { version = "0.7.5", features = ["async"] } - -[target.'cfg(target_os="windows")'.dependencies] -iced = { version = "0.13.1", features = ["tokio"] } -dirs = "5.0.1" -tray-item = "0.10.0" - -[target.'cfg(target_os="windows")'.build-dependencies] -embed-resource = "2.3" - -[target.'cfg(target_os="android")'.dependencies] -jni = "^0.20" -robusta_jni = "0.2.2" -nonblock = "0.2.0" -log4rs = "1.3.0" \ No newline at end of file +readme = "README.md" \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..0ad25db --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/Cargo.lock b/frida_core/Cargo.lock similarity index 100% rename from Cargo.lock rename to frida_core/Cargo.lock diff --git a/frida_core/Cargo.toml b/frida_core/Cargo.toml new file mode 100644 index 0000000..04f4dd3 --- /dev/null +++ b/frida_core/Cargo.toml @@ -0,0 +1,60 @@ +[package] +name = "frida_core" +version.workspace = true +edition.workspace = true +license-file.workspace = true +authors.workspace = true +keywords.workspace = true +categories.workspace = true +readme.workspace = true + +[lib] +crate-type = ["cdylib"] +path = "src/android.rs" + +[[bin]] +name = "frida-cli" +path = "src/main.rs" + +[[bin]] +name = "frida-gui" +path = "src/gui/mod.rs" + +[dependencies] +clap = "2.33" +aes-gcm = "0.10.3" +tokio = { version = "1", features = ["full", "signal", "tracing"] } +tokio-util = "0.7.12" +serde = "1.0" +serde_derive = "1.0.190" +rand = { version = "0.8.5", features = ["small_rng", "getrandom", "std_rng"] } +block-modes = "0.8" +block-padding = "0.2" +generic-array = "0.14" +env_logger = "0.9" +log = "0.4.20" +futures = "0.3.30" +packet = "0.1.4" +async-channel = "2.3.1" +hex = "0.4" +serde_yaml = "0.9.34" +x25519-dalek = { version = "2.0.1", features = ["getrandom", "static_secrets"] } +base64 = "0.22.1" +chrono = "0.4.38" +console-subscriber = "0.4.0" +network-interface = "2.0.0" +tun = { version = "0.7.5", features = ["async"] } + +[target.'cfg(target_os="windows")'.dependencies] +iced = { version = "0.13.1", features = ["tokio"] } +dirs = "5.0.1" +tray-item = "0.10.0" + +[target.'cfg(target_os="windows")'.build-dependencies] +embed-resource = "2.3" + +[target.'cfg(target_os="android")'.dependencies] +jni = "^0.20" +robusta_jni = "0.2.2" +nonblock = "0.2.0" +log4rs = "1.3.0" \ No newline at end of file diff --git a/build.rs b/frida_core/build.rs similarity index 100% rename from build.rs rename to frida_core/build.rs diff --git a/icons/off.ico b/frida_core/icons/off.ico similarity index 100% rename from icons/off.ico rename to frida_core/icons/off.ico diff --git a/icons/on.ico b/frida_core/icons/on.ico similarity index 100% rename from icons/on.ico rename to frida_core/icons/on.ico diff --git a/src/android.rs b/frida_core/src/android.rs similarity index 100% rename from src/android.rs rename to frida_core/src/android.rs diff --git a/src/client.rs b/frida_core/src/client.rs similarity index 97% rename from src/client.rs rename to frida_core/src/client.rs index b61883b..b2978db 100644 --- a/src/client.rs +++ b/frida_core/src/client.rs @@ -1,382 +1,382 @@ - -pub mod general { - use crate::config::ClientConfiguration; - use async_channel::{Receiver, Sender}; - use futures::{stream::{SplitSink, SplitStream}, SinkExt, StreamExt}; - use tokio_util::{codec::Framed, sync::CancellationToken}; - use tokio::{net::UdpSocket, sync::{Mutex, mpsc}, io::{AsyncWriteExt, AsyncReadExt}, fs::File}; - use log::{error, info, warn}; - use aes_gcm::{ - aead::{Aead, AeadCore, KeyInit, OsRng}, - Aes256Gcm, Nonce}; - use base64::prelude::*; - use std::{io::{Read, Write}, sync::Arc}; - use std::net::Ipv4Addr; - - use x25519_dalek::{PublicKey, StaticSecret}; - use crate::udp::{UDPVpnPacket, UDPVpnHandshake, UDPSerializable}; - - use tun::{ AsyncDevice, DeviceReader, DeviceWriter, TunPacketCodec }; - - pub trait ReadWrapper { - async fn read(&mut self, buf: &mut Vec) -> Result; - } - - pub struct DevReader { - pub dr: SplitStream> - } - - // TODO: implement custom Error - impl ReadWrapper for DevReader { - async fn read(&mut self, buf: &mut Vec) -> Result { - if let Some(Ok(tb)) = self.dr.next().await { - *buf = tb; - return Ok(buf.len()); - } - Err(()) - } - } - - pub struct FdReader { - pub br: File - } - - impl ReadWrapper for FdReader { - async fn read(&mut self, buf: &mut Vec) -> Result { - let r = self.br.read(buf).await; - if let Ok(a) = r { - return Ok(a); - } - Err(()) - } - } - - pub trait WriteWrapper { - async fn write(&mut self, msg: WriterMessage) -> Result; - } - - pub enum WriterMessage { - Plain(Vec), - Gateway(Ipv4Addr) - } - - pub struct DevWriter { - pub dr: SplitSink, Vec> - } - - // TODO: implement custom Error - impl WriteWrapper for DevWriter { - async fn write(&mut self, msg: WriterMessage) -> Result { - match msg { - WriterMessage::Plain(buf) => { - let l = buf.len(); - return match self.dr.send(buf).await { - Ok(()) => Ok(l), - Err(e) => Err(e.to_string()) - }; - }, - // this thing should be abolished later - WriterMessage::Gateway(_addr) => { - Ok(0) - } - } - } - } - - pub struct FdWriter { - pub br: File - } - - impl WriteWrapper for FdWriter { - async fn write(&mut self, msg: WriterMessage) -> Result { - match msg { - WriterMessage::Plain(buf) => { - if let Ok(a) = self.br.write(&buf).await { - return Ok(a); - } - Err(String::new()) - }, - WriterMessage::Gateway(_addr) => {Ok(0)} - } - } - } - - pub trait VpnClient { - async fn start(&self); - } - - pub struct CoreVpnClient where T: ReadWrapper, R: WriteWrapper { - pub client_config: ClientConfiguration, - pub dev_reader: T, - pub dev_writer: R, - pub close_token: CancellationToken - } - - impl CoreVpnClient { - pub async fn start(&mut self, sock: UdpSocket) { - info!("Starting client..."); - - let dr_cancel: CancellationToken = CancellationToken::new(); - let sr_cancel: CancellationToken = CancellationToken::new(); - - let sock_rec = Arc::new(sock); - let sock_snd = sock_rec.clone(); - - let (tx, mut rx) = mpsc::unbounded_channel::>(); - let (dx, mut mx) = mpsc::unbounded_channel::>(); - - let cipher_shared: Arc>> = Arc::new(Mutex::new(None)); - - let priv_key = BASE64_STANDARD.decode(&self.client_config.client.private_key).unwrap(); - - let cipher_shared_clone = cipher_shared.clone(); - - let pkey = BASE64_STANDARD.decode(&self.client_config.client.public_key).unwrap(); - let handshake = UDPVpnHandshake{ public_key: pkey, request_ip: self.client_config.client.address.parse::().unwrap() }; - let mut nz = 0; - while nz < 25 { - sock_snd.send(&handshake.serialize()).await.unwrap(); - nz += 1 - } - //sock_snd.send(&handshake.serialize()).await.unwrap(); - - let s_cipher = cipher_shared.clone(); - - let _ = self.dev_writer.write(WriterMessage::Plain(handshake.serialize())).await; - - let mut buf = vec![0; 1400]; // mtu - let mut buf1 = vec![0; 4096]; // should be changed to less bytes - - loop { - tokio::select! { - _ = self.close_token.cancelled() => { - info!("Cancellation token has been thrown"); - sr_cancel.cancel(); - dr_cancel.cancel(); - return; - } - rr = rx.recv() => { - if let Some(bytes) = rr { - info!("Write to tun. len={:?}", bytes.len()); - - if let Err(e) = self.dev_writer.write(WriterMessage::Plain(bytes)).await { - error!("Writing error: {:?}", e); - } - /* if let Err(e) = self.dev_writer.flush().await { - error!("Flushing error: {:?}", e); - }*/ - } - } - rr2 = mx.recv() => { - if let Some(bytes) = rr2 { - let s_c = s_cipher.lock().await; - - if s_c.is_some() { - let aes = Aes256Gcm::new(s_c.as_ref().unwrap().as_bytes().into()); - let nonce = Aes256Gcm::generate_nonce(&mut OsRng); - let ciphered_data = aes.encrypt(&nonce, &bytes[..]); - - if let Ok(ciphered_d) = ciphered_data { - let vpn_packet = UDPVpnPacket{ data: ciphered_d, nonce: nonce.to_vec()}; - let serialized_data = vpn_packet.serialize(); - info!("Write to socket"); - sock_snd.send(&serialized_data).await.unwrap(); - } else { - error!("Socket encryption failed."); - } - } else { - error!("There is no shared_secret in main loop"); - } - } - } - rr = self.dev_reader.read(&mut buf) => { - if let Ok(n) = rr { - info!("Read from tun."); // hex::encode(&buf[..n]) - dx.send(buf[..n].to_vec()).unwrap(); - } - } - rr = sock_rec.recv(&mut buf1) => { - if let Ok(l) = rr { - info!("Read from socket"); - let mut s_cipher = cipher_shared_clone.lock().await; - match buf1.first() { - Some(h) => { - match h { - 0 => { - let handshake = UDPVpnHandshake::deserialize(&(buf1[..l].to_vec())); - let mut k = [0u8; 32]; - for (&x, p) in handshake.public_key.iter().zip(k.iter_mut()) { - *p = x; - } - let mut k1 = [0u8; 32]; - for (&x, p) in priv_key.iter().zip(k1.iter_mut()) { - *p = x; - } - *s_cipher = Some(StaticSecret::from(k1) - .diffie_hellman(&PublicKey::from(k))); - }, // handshake - 1 => { - let wrapped_packet = UDPVpnPacket::deserialize(&(buf1[..l].to_vec())); - if s_cipher.is_some() { - let aes = Aes256Gcm::new(s_cipher.as_ref().unwrap().as_bytes().into()); - let nonce = Nonce::clone_from_slice(&wrapped_packet.nonce); - match aes.decrypt(&nonce, &wrapped_packet.data[..]) { - Ok(decrypted) => { let _ = tx.send(decrypted); }, - Err(error) => { error!("Decryption error! {:?}", error); } - } - } else { - warn!("There is no static_secret"); - } - }, // payload - 2 => { info!("Got keepalive packet"); }, - _ => { error!("Unexpected header value."); } - } - }, - None => { error!("There is no header."); } - } - drop(s_cipher); - } - } - }; - } - } - } -} - -pub mod android { - #![cfg(target_os = "android")] - use crate::client::general::{VpnClient, CoreVpnClient, FdReader, FdWriter}; - use crate::config::ClientConfiguration; - use tokio_util::sync::CancellationToken; - use std::os::fd::FromRawFd; - use tokio::{net::UdpSocket, sync::{Mutex, mpsc}, io::{BufReader, BufWriter, AsyncWriteExt, AsyncReadExt}, fs::File}; - use log::{error, info, warn}; - - pub struct AndroidClient { - pub client_config: ClientConfiguration, - pub fd: i32, - pub close_token: CancellationToken - } - - impl VpnClient for AndroidClient { - async fn start(&self) { - info!("FD: {:?}", &self.fd); - let mut dev = unsafe { File::from_raw_fd(self.fd) }; - let mut dev1 = unsafe { File::from_raw_fd(self.fd) }; - let mut client = CoreVpnClient{client_config: self.client_config.clone(), dev_reader: FdReader{br: dev}, dev_writer: FdWriter{br: dev1}, close_token: self.close_token.clone()}; - info!("SSS: {:?}", &self.client_config.server.endpoint); - let sock = UdpSocket::bind("0.0.0.0:0").await.unwrap(); - sock.connect(&self.client_config.server.endpoint).await.unwrap(); - client.start(sock).await; - } - } -} - -pub mod desktop { - use crate::client::general::{CoreVpnClient, DevReader, DevWriter, VpnClient}; - use crate::config::ClientConfiguration; - use futures::{SinkExt, StreamExt}; - use log::info; - use tokio::net::UdpSocket; - use tokio::sync::Mutex; - - #[cfg(target_os = "linux")] - use network_interface::{NetworkInterface, NetworkInterfaceConfig}; - - use tun::{ Configuration, create_as_async }; - - - #[cfg(target_os = "linux")] - fn configure_routes(endpoint_ip: &str, s_interface: Option) { - let interfaces = NetworkInterface::show().unwrap(); - - let net_inter = interfaces.iter() - .filter(|i| !i.addr.iter().any(|b| b.ip().to_string() == "127.0.0.1" || b.ip().to_string() == "::1") ) - .min_by(|x, y| x.index.cmp(&y.index)) - .unwrap(); - - let inter_name = if s_interface.is_some() { s_interface.unwrap() } else { net_inter.name.clone() }; - - info!("Main network interface: {:?}", inter_name); - - /*let mut ip_output = std::process::Command::new("sudo") - .arg("ip") - .arg("route") - .arg("del") - .arg("default") - .output() - .expect("Failed to delete default gateway."); - - if !ip_output.status.success() { - error!("Failed to delete default gateway: {:?}", String::from_utf8_lossy(&ip_output.stderr)); - }*/ - - let mut ip_output = std::process::Command::new("sudo") - .arg("ip") - .arg("-4") - .arg("route") - .arg("add") - .arg("0.0.0.0/0") - .arg("dev") - .arg("tun0") - .output() - .expect("Failed to execute ip route command."); - - if !ip_output.status.success() { - log::error!("Failed to route all traffic: {:?}", String::from_utf8_lossy(&ip_output.stderr)); - } - // TODO: replace 192.168.0.1 with relative variable - ip_output = std::process::Command::new("sudo") - .arg("ip") - .arg("route") - .arg("add") - .arg(endpoint_ip.to_owned()+"/32") - .arg("via") - .arg("192.168.0.1") - .arg("dev") - .arg(inter_name) - .output() - .expect("Failed to make exception for vpns endpoint."); - - if !ip_output.status.success() { - log::error!("Failed to forward packets: {:?}", String::from_utf8_lossy(&ip_output.stderr)); - } - } - - pub struct DesktopClient { - pub client_config: ClientConfiguration, - pub s_interface: Option - } - - impl VpnClient for DesktopClient { - async fn start(&self) { - info!("s_interface: {:?}", &self.s_interface); - info!("client_address: {:?}", &self.client_config.client.address); - let mut config = Configuration::default(); - config.address(&self.client_config.client.address) - .netmask("255.255.255.255") - .destination("10.66.66.1") - .mtu(1400) - .tun_name("tun0") - .up(); - - info!("SSS: {:?}", &self.client_config.server.endpoint); - let sock = UdpSocket::bind(("0.0.0.0", 0)).await.unwrap(); - sock.connect(&self.client_config.server.endpoint).await.unwrap(); - - let dev = create_as_async(&config).unwrap(); - let (mut dev_writer , mut dev_reader) = dev.into_framed().split(); - - let mut client = CoreVpnClient{ client_config: self.client_config.clone(), dev_reader: DevReader{ dr: dev_reader }, dev_writer: DevWriter{dr: dev_writer }, close_token: tokio_util::sync::CancellationToken::new()}; - - info!("Platform specific code"); - /* #[cfg(target_os = "linux")] - { - let s_a: std::net::SocketAddr = self.client_config.server.endpoint.parse().unwrap(); - configure_routes(&s_a.ip().to_string(), self.s_interface.clone()); - }*/ - - client.start(sock).await; - } - } + +pub mod general { + use crate::config::ClientConfiguration; + use async_channel::{Receiver, Sender}; + use futures::{stream::{SplitSink, SplitStream}, SinkExt, StreamExt}; + use tokio_util::{codec::Framed, sync::CancellationToken}; + use tokio::{net::UdpSocket, sync::{Mutex, mpsc}, io::{AsyncWriteExt, AsyncReadExt}, fs::File}; + use log::{error, info, warn}; + use aes_gcm::{ + aead::{Aead, AeadCore, KeyInit, OsRng}, + Aes256Gcm, Nonce}; + use base64::prelude::*; + use std::{io::{Read, Write}, sync::Arc}; + use std::net::Ipv4Addr; + + use x25519_dalek::{PublicKey, StaticSecret}; + use crate::udp::{UDPVpnPacket, UDPVpnHandshake, UDPSerializable}; + + use tun::{ AsyncDevice, DeviceReader, DeviceWriter, TunPacketCodec }; + + pub trait ReadWrapper { + async fn read(&mut self, buf: &mut Vec) -> Result; + } + + pub struct DevReader { + pub dr: SplitStream> + } + + // TODO: implement custom Error + impl ReadWrapper for DevReader { + async fn read(&mut self, buf: &mut Vec) -> Result { + if let Some(Ok(tb)) = self.dr.next().await { + *buf = tb; + return Ok(buf.len()); + } + Err(()) + } + } + + pub struct FdReader { + pub br: File + } + + impl ReadWrapper for FdReader { + async fn read(&mut self, buf: &mut Vec) -> Result { + let r = self.br.read(buf).await; + if let Ok(a) = r { + return Ok(a); + } + Err(()) + } + } + + pub trait WriteWrapper { + async fn write(&mut self, msg: WriterMessage) -> Result; + } + + pub enum WriterMessage { + Plain(Vec), + Gateway(Ipv4Addr) + } + + pub struct DevWriter { + pub dr: SplitSink, Vec> + } + + // TODO: implement custom Error + impl WriteWrapper for DevWriter { + async fn write(&mut self, msg: WriterMessage) -> Result { + match msg { + WriterMessage::Plain(buf) => { + let l = buf.len(); + return match self.dr.send(buf).await { + Ok(()) => Ok(l), + Err(e) => Err(e.to_string()) + }; + }, + // this thing should be abolished later + WriterMessage::Gateway(_addr) => { + Ok(0) + } + } + } + } + + pub struct FdWriter { + pub br: File + } + + impl WriteWrapper for FdWriter { + async fn write(&mut self, msg: WriterMessage) -> Result { + match msg { + WriterMessage::Plain(buf) => { + if let Ok(a) = self.br.write(&buf).await { + return Ok(a); + } + Err(String::new()) + }, + WriterMessage::Gateway(_addr) => {Ok(0)} + } + } + } + + pub trait VpnClient { + async fn start(&self); + } + + pub struct CoreVpnClient where T: ReadWrapper, R: WriteWrapper { + pub client_config: ClientConfiguration, + pub dev_reader: T, + pub dev_writer: R, + pub close_token: CancellationToken + } + + impl CoreVpnClient { + pub async fn start(&mut self, sock: UdpSocket) { + info!("Starting client..."); + + let dr_cancel: CancellationToken = CancellationToken::new(); + let sr_cancel: CancellationToken = CancellationToken::new(); + + let sock_rec = Arc::new(sock); + let sock_snd = sock_rec.clone(); + + let (tx, mut rx) = mpsc::unbounded_channel::>(); + let (dx, mut mx) = mpsc::unbounded_channel::>(); + + let cipher_shared: Arc>> = Arc::new(Mutex::new(None)); + + let priv_key = BASE64_STANDARD.decode(&self.client_config.client.private_key).unwrap(); + + let cipher_shared_clone = cipher_shared.clone(); + + let pkey = BASE64_STANDARD.decode(&self.client_config.client.public_key).unwrap(); + let handshake = UDPVpnHandshake{ public_key: pkey, request_ip: self.client_config.client.address.parse::().unwrap() }; + let mut nz = 0; + while nz < 25 { + sock_snd.send(&handshake.serialize()).await.unwrap(); + nz += 1 + } + //sock_snd.send(&handshake.serialize()).await.unwrap(); + + let s_cipher = cipher_shared.clone(); + + let _ = self.dev_writer.write(WriterMessage::Plain(handshake.serialize())).await; + + let mut buf = vec![0; 1400]; // mtu + let mut buf1 = vec![0; 4096]; // should be changed to less bytes + + loop { + tokio::select! { + _ = self.close_token.cancelled() => { + info!("Cancellation token has been thrown"); + sr_cancel.cancel(); + dr_cancel.cancel(); + return; + } + rr = rx.recv() => { + if let Some(bytes) = rr { + info!("Write to tun. len={:?}", bytes.len()); + + if let Err(e) = self.dev_writer.write(WriterMessage::Plain(bytes)).await { + error!("Writing error: {:?}", e); + } + /* if let Err(e) = self.dev_writer.flush().await { + error!("Flushing error: {:?}", e); + }*/ + } + } + rr2 = mx.recv() => { + if let Some(bytes) = rr2 { + let s_c = s_cipher.lock().await; + + if s_c.is_some() { + let aes = Aes256Gcm::new(s_c.as_ref().unwrap().as_bytes().into()); + let nonce = Aes256Gcm::generate_nonce(&mut OsRng); + let ciphered_data = aes.encrypt(&nonce, &bytes[..]); + + if let Ok(ciphered_d) = ciphered_data { + let vpn_packet = UDPVpnPacket{ data: ciphered_d, nonce: nonce.to_vec()}; + let serialized_data = vpn_packet.serialize(); + info!("Write to socket"); + sock_snd.send(&serialized_data).await.unwrap(); + } else { + error!("Socket encryption failed."); + } + } else { + error!("There is no shared_secret in main loop"); + } + } + } + rr = self.dev_reader.read(&mut buf) => { + if let Ok(n) = rr { + info!("Read from tun."); // hex::encode(&buf[..n]) + dx.send(buf[..n].to_vec()).unwrap(); + } + } + rr = sock_rec.recv(&mut buf1) => { + if let Ok(l) = rr { + info!("Read from socket"); + let mut s_cipher = cipher_shared_clone.lock().await; + match buf1.first() { + Some(h) => { + match h { + 0 => { + let handshake = UDPVpnHandshake::deserialize(&(buf1[..l].to_vec())); + let mut k = [0u8; 32]; + for (&x, p) in handshake.public_key.iter().zip(k.iter_mut()) { + *p = x; + } + let mut k1 = [0u8; 32]; + for (&x, p) in priv_key.iter().zip(k1.iter_mut()) { + *p = x; + } + *s_cipher = Some(StaticSecret::from(k1) + .diffie_hellman(&PublicKey::from(k))); + }, // handshake + 1 => { + let wrapped_packet = UDPVpnPacket::deserialize(&(buf1[..l].to_vec())); + if s_cipher.is_some() { + let aes = Aes256Gcm::new(s_cipher.as_ref().unwrap().as_bytes().into()); + let nonce = Nonce::clone_from_slice(&wrapped_packet.nonce); + match aes.decrypt(&nonce, &wrapped_packet.data[..]) { + Ok(decrypted) => { let _ = tx.send(decrypted); }, + Err(error) => { error!("Decryption error! {:?}", error); } + } + } else { + warn!("There is no static_secret"); + } + }, // payload + 2 => { info!("Got keepalive packet"); }, + _ => { error!("Unexpected header value."); } + } + }, + None => { error!("There is no header."); } + } + drop(s_cipher); + } + } + }; + } + } + } +} + +pub mod android { + #![cfg(target_os = "android")] + use crate::client::general::{VpnClient, CoreVpnClient, FdReader, FdWriter}; + use crate::config::ClientConfiguration; + use tokio_util::sync::CancellationToken; + use std::os::fd::FromRawFd; + use tokio::{net::UdpSocket, sync::{Mutex, mpsc}, io::{BufReader, BufWriter, AsyncWriteExt, AsyncReadExt}, fs::File}; + use log::{error, info, warn}; + + pub struct AndroidClient { + pub client_config: ClientConfiguration, + pub fd: i32, + pub close_token: CancellationToken + } + + impl VpnClient for AndroidClient { + async fn start(&self) { + info!("FD: {:?}", &self.fd); + let mut dev = unsafe { File::from_raw_fd(self.fd) }; + let mut dev1 = unsafe { File::from_raw_fd(self.fd) }; + let mut client = CoreVpnClient{client_config: self.client_config.clone(), dev_reader: FdReader{br: dev}, dev_writer: FdWriter{br: dev1}, close_token: self.close_token.clone()}; + info!("SSS: {:?}", &self.client_config.server.endpoint); + let sock = UdpSocket::bind("0.0.0.0:0").await.unwrap(); + sock.connect(&self.client_config.server.endpoint).await.unwrap(); + client.start(sock).await; + } + } +} + +pub mod desktop { + use crate::client::general::{CoreVpnClient, DevReader, DevWriter, VpnClient}; + use crate::config::ClientConfiguration; + use futures::{SinkExt, StreamExt}; + use log::info; + use tokio::net::UdpSocket; + use tokio::sync::Mutex; + + #[cfg(target_os = "linux")] + use network_interface::{NetworkInterface, NetworkInterfaceConfig}; + + use tun::{ Configuration, create_as_async }; + + + #[cfg(target_os = "linux")] + fn configure_routes(endpoint_ip: &str, s_interface: Option) { + let interfaces = NetworkInterface::show().unwrap(); + + let net_inter = interfaces.iter() + .filter(|i| !i.addr.iter().any(|b| b.ip().to_string() == "127.0.0.1" || b.ip().to_string() == "::1") ) + .min_by(|x, y| x.index.cmp(&y.index)) + .unwrap(); + + let inter_name = if s_interface.is_some() { s_interface.unwrap() } else { net_inter.name.clone() }; + + info!("Main network interface: {:?}", inter_name); + + /*let mut ip_output = std::process::Command::new("sudo") + .arg("ip") + .arg("route") + .arg("del") + .arg("default") + .output() + .expect("Failed to delete default gateway."); + + if !ip_output.status.success() { + error!("Failed to delete default gateway: {:?}", String::from_utf8_lossy(&ip_output.stderr)); + }*/ + + let mut ip_output = std::process::Command::new("sudo") + .arg("ip") + .arg("-4") + .arg("route") + .arg("add") + .arg("0.0.0.0/0") + .arg("dev") + .arg("tun0") + .output() + .expect("Failed to execute ip route command."); + + if !ip_output.status.success() { + log::error!("Failed to route all traffic: {:?}", String::from_utf8_lossy(&ip_output.stderr)); + } + // TODO: replace 192.168.0.1 with relative variable + ip_output = std::process::Command::new("sudo") + .arg("ip") + .arg("route") + .arg("add") + .arg(endpoint_ip.to_owned()+"/32") + .arg("via") + .arg("192.168.0.1") + .arg("dev") + .arg(inter_name) + .output() + .expect("Failed to make exception for vpns endpoint."); + + if !ip_output.status.success() { + log::error!("Failed to forward packets: {:?}", String::from_utf8_lossy(&ip_output.stderr)); + } + } + + pub struct DesktopClient { + pub client_config: ClientConfiguration, + pub s_interface: Option + } + + impl VpnClient for DesktopClient { + async fn start(&self) { + info!("s_interface: {:?}", &self.s_interface); + info!("client_address: {:?}", &self.client_config.client.address); + let mut config = Configuration::default(); + config.address(&self.client_config.client.address) + .netmask("255.255.255.255") + .destination("10.66.66.1") + .mtu(1400) + .tun_name("tun0") + .up(); + + info!("SSS: {:?}", &self.client_config.server.endpoint); + let sock = UdpSocket::bind(("0.0.0.0", 0)).await.unwrap(); + sock.connect(&self.client_config.server.endpoint).await.unwrap(); + + let dev = create_as_async(&config).unwrap(); + let (mut dev_writer , mut dev_reader) = dev.into_framed().split(); + + let mut client = CoreVpnClient{ client_config: self.client_config.clone(), dev_reader: DevReader{ dr: dev_reader }, dev_writer: DevWriter{dr: dev_writer }, close_token: tokio_util::sync::CancellationToken::new()}; + + info!("Platform specific code"); + /* #[cfg(target_os = "linux")] + { + let s_a: std::net::SocketAddr = self.client_config.server.endpoint.parse().unwrap(); + configure_routes(&s_a.ip().to_string(), self.s_interface.clone()); + }*/ + + client.start(sock).await; + } + } } \ No newline at end of file diff --git a/src/config/mod.rs b/frida_core/src/config/mod.rs similarity index 100% rename from src/config/mod.rs rename to frida_core/src/config/mod.rs diff --git a/src/gui/mod.rs b/frida_core/src/gui/mod.rs similarity index 100% rename from src/gui/mod.rs rename to frida_core/src/gui/mod.rs diff --git a/src/gui/tab/mod.rs b/frida_core/src/gui/tab/mod.rs similarity index 100% rename from src/gui/tab/mod.rs rename to frida_core/src/gui/tab/mod.rs diff --git a/src/gui/tab_button.rs b/frida_core/src/gui/tab_button.rs similarity index 100% rename from src/gui/tab_button.rs rename to frida_core/src/gui/tab_button.rs diff --git a/src/gui/tab_panel.rs b/frida_core/src/gui/tab_panel.rs similarity index 100% rename from src/gui/tab_panel.rs rename to frida_core/src/gui/tab_panel.rs diff --git a/src/main.rs b/frida_core/src/main.rs similarity index 97% rename from src/main.rs rename to frida_core/src/main.rs index f982df1..9398267 100644 --- a/src/main.rs +++ b/frida_core/src/main.rs @@ -1,171 +1,171 @@ - -use std::{fs, net::{Ipv4Addr}, str}; -use clap::{App, Arg, ArgMatches}; -use env_logger::Builder; -use log::{error, LevelFilter}; -use crate::config::{ ServerConfiguration, ClientConfiguration, ObfsProtocol, ServerPeer }; -use crate::client::{desktop::DesktopClient, general::VpnClient}; - -mod obfs; -mod server; -mod client; -mod udp; -mod config; - -fn generate_server_config(matches: &ArgMatches, config_path: &str) { - let bind_address = matches.value_of("bind-address").expect("No bind address specified"); - let internal_address = matches.value_of("internal-address").expect("No internal address specified"); - let broadcast_mode = matches.value_of("broadcast-mode").is_some(); - let keepalive: u8 = matches.value_of("keepalive").unwrap().parse().expect("Keepalive argument should be a number"); - let obfs_type = match matches.value_of("obfs-type").expect("Obfs type should be specified") { - "dns" => ObfsProtocol::FakeDNS, - "veil" => ObfsProtocol::VEIL, - "xor" => ObfsProtocol::XOR, - _ => ObfsProtocol::NONE - }; - - let _ = fs::write(config_path, serde_yaml::to_string(&ServerConfiguration::default(bind_address, internal_address, broadcast_mode, keepalive, obfs_type)).unwrap()); -} - -fn generate_peer_config(matches: &ArgMatches, config_path: &str, cfg_raw: &String) { - let keepalive: u8 = matches.value_of("keepalive").unwrap().parse().expect("Keepalive argument should be a number"); - let grab_endpoint = matches.value_of("grab-endpoint").is_some(); - let endpoint = matches.value_of("endpoint").or(Some("0.0.0.0:0")).unwrap(); - let peer_cfg = matches.value_of("peer-cfg").expect("No peer cfg path specified"); - - let mut config: ServerConfiguration = serde_yaml::from_str(cfg_raw).expect("Bad server config file structure"); - - let prs = &mut config.peers[..]; - prs.sort_by(|a, b| a.ip.octets()[3].cmp(&b.ip.octets()[3])); - - let mut internal_address = prs.iter() - .map(|p| p.ip) - .collect::>() - .first() - .or(Some(&config.interface.internal_address.parse::().unwrap())) - .unwrap() - .clone(); - - internal_address = Ipv4Addr::new(internal_address.octets()[0], internal_address.octets()[1], internal_address.octets()[2], internal_address.octets()[3]+1); - - let cl_cfg = &ClientConfiguration::default(if grab_endpoint { &config.interface.bind_address } else { endpoint }, - keepalive, - &config.interface.public_key, - &internal_address.to_string()); - - config.peers.push(ServerPeer { public_key: cl_cfg.client.public_key.clone(), ip: internal_address.clone() }); - - let _ = fs::write(peer_cfg, serde_yaml::to_string(cl_cfg).unwrap()); - - let _ = fs::write(config_path, serde_yaml::to_string(&config).unwrap()); -} - -async fn init_server(cfg_raw: &str, s_interface: Option<&str>) { - let config: ServerConfiguration = serde_yaml::from_str(cfg_raw).expect("Bad server config file structure"); - server::server_mode(config, s_interface).await; -} - -async fn init_client(cfg_raw: &str, s_interface: Option) { - let config: ClientConfiguration = serde_yaml::from_str(cfg_raw).expect("Bad client config file structure"); - //client::client_mode(config, s_interface).await; - let client = DesktopClient{client_config: config, s_interface}; - client.start().await; -} - -#[tokio::main] -async fn main() { - //console_subscriber::init(); - - // Initialize the logger with 'info' as the default level - Builder::new() - .filter(None, LevelFilter::Info) - .init(); - - let matches = App::new("Frida") - .version("0.1.2") - .author("alterwain") - .about("VPN software") - .arg(Arg::with_name("mode") - .required(true) - .index(1) - .possible_values(&["server", "client", "gen_cfg", "new_peer"]) - .help("Runs the program in certain mode")) - .arg(Arg::with_name("config") - .long("config") - .required(true) - .value_name("FILE") - .help("The path to VPN configuration file") - .takes_value(true)) - .arg(Arg::with_name("peer-cfg") - .long("peer-cfg") - .value_name("FILE") - .help("The path to VPN peer configuration file") - .takes_value(true)) - .arg(Arg::with_name("bind-address") - .long("bind-address") - .value_name("IP:PORT") - .help("The ip:port that would be used to bind server (config)") - .takes_value(true)) - .arg(Arg::with_name("endpoint") - .long("endpoint") - .value_name("IP:PORT") - .help("The ip:port that would be used by client to connect (config)") - .takes_value(true)) - .arg(Arg::with_name("internal-address") - .long("internal-address") - .value_name("IP") - .help("The address of VPN server in it's subnet (config)") - .takes_value(true)) - .arg(Arg::with_name("broadcast-mode") - .long("broadcast-mode") - .help("If set to true, then all incoming traffic with an unknown destination address will be forwarded to all peers (config)") - .takes_value(false)) - .arg(Arg::with_name("grab-endpoint") - .long("grab-endpoint") - .help("If set to true, the endpoint address for peers will be grabbed from server config (config)") - .takes_value(false)) - .arg(Arg::with_name("keepalive") - .long("keepalive") - .required(false) - .value_name("SECONDS") - .default_value("0") - .help("Keepalive packets interval (config)") - .takes_value(true)) - .arg(Arg::with_name("obfs-type") - .long("obfs-type") - .possible_values(&["dns", "veil", "xor"]) - .takes_value(true) - .value_name("OBFS") - .help("Obfuscation protocol (config)")) - .arg(Arg::with_name("interface") - .long("interface") - .required(false) - .takes_value(true) - .value_name("NAME") - .help("Explicitly set network interface name for routing")) - .get_matches(); - - let mode = matches.value_of("mode").unwrap(); - - if let Some(config_path) = matches.value_of("config") { - - let data = fs::read(config_path); - - if data.is_err() { - match mode { - "gen_cfg" => generate_server_config(&matches, config_path), - _ => error!("There is no config file.") - } - return; - } - - let cfg_raw = &String::from_utf8(data.unwrap()).unwrap(); - - match mode { - "server" => init_server(cfg_raw, matches.value_of("interface")).await, - "client" => init_client(cfg_raw, matches.value_of("interface").map_or(None, |x| Some(String::from(x)))).await, - "new_peer" => generate_peer_config(&matches, config_path, cfg_raw), - _ => error!("There is config file already") - } - } + +use std::{fs, net::{Ipv4Addr}, str}; +use clap::{App, Arg, ArgMatches}; +use env_logger::Builder; +use log::{error, LevelFilter}; +use crate::config::{ ServerConfiguration, ClientConfiguration, ObfsProtocol, ServerPeer }; +use crate::client::{desktop::DesktopClient, general::VpnClient}; + +mod obfs; +mod server; +mod client; +mod udp; +mod config; + +fn generate_server_config(matches: &ArgMatches, config_path: &str) { + let bind_address = matches.value_of("bind-address").expect("No bind address specified"); + let internal_address = matches.value_of("internal-address").expect("No internal address specified"); + let broadcast_mode = matches.value_of("broadcast-mode").is_some(); + let keepalive: u8 = matches.value_of("keepalive").unwrap().parse().expect("Keepalive argument should be a number"); + let obfs_type = match matches.value_of("obfs-type").expect("Obfs type should be specified") { + "dns" => ObfsProtocol::FakeDNS, + "veil" => ObfsProtocol::VEIL, + "xor" => ObfsProtocol::XOR, + _ => ObfsProtocol::NONE + }; + + let _ = fs::write(config_path, serde_yaml::to_string(&ServerConfiguration::default(bind_address, internal_address, broadcast_mode, keepalive, obfs_type)).unwrap()); +} + +fn generate_peer_config(matches: &ArgMatches, config_path: &str, cfg_raw: &String) { + let keepalive: u8 = matches.value_of("keepalive").unwrap().parse().expect("Keepalive argument should be a number"); + let grab_endpoint = matches.value_of("grab-endpoint").is_some(); + let endpoint = matches.value_of("endpoint").or(Some("0.0.0.0:0")).unwrap(); + let peer_cfg = matches.value_of("peer-cfg").expect("No peer cfg path specified"); + + let mut config: ServerConfiguration = serde_yaml::from_str(cfg_raw).expect("Bad server config file structure"); + + let prs = &mut config.peers[..]; + prs.sort_by(|a, b| a.ip.octets()[3].cmp(&b.ip.octets()[3])); + + let mut internal_address = prs.iter() + .map(|p| p.ip) + .collect::>() + .first() + .or(Some(&config.interface.internal_address.parse::().unwrap())) + .unwrap() + .clone(); + + internal_address = Ipv4Addr::new(internal_address.octets()[0], internal_address.octets()[1], internal_address.octets()[2], internal_address.octets()[3]+1); + + let cl_cfg = &ClientConfiguration::default(if grab_endpoint { &config.interface.bind_address } else { endpoint }, + keepalive, + &config.interface.public_key, + &internal_address.to_string()); + + config.peers.push(ServerPeer { public_key: cl_cfg.client.public_key.clone(), ip: internal_address.clone() }); + + let _ = fs::write(peer_cfg, serde_yaml::to_string(cl_cfg).unwrap()); + + let _ = fs::write(config_path, serde_yaml::to_string(&config).unwrap()); +} + +async fn init_server(cfg_raw: &str, s_interface: Option<&str>) { + let config: ServerConfiguration = serde_yaml::from_str(cfg_raw).expect("Bad server config file structure"); + server::server_mode(config, s_interface).await; +} + +async fn init_client(cfg_raw: &str, s_interface: Option) { + let config: ClientConfiguration = serde_yaml::from_str(cfg_raw).expect("Bad client config file structure"); + //client::client_mode(config, s_interface).await; + let client = DesktopClient{client_config: config, s_interface}; + client.start().await; +} + +#[tokio::main] +async fn main() { + //console_subscriber::init(); + + // Initialize the logger with 'info' as the default level + Builder::new() + .filter(None, LevelFilter::Info) + .init(); + + let matches = App::new("Frida") + .version("0.1.2") + .author("alterwain") + .about("VPN software") + .arg(Arg::with_name("mode") + .required(true) + .index(1) + .possible_values(&["server", "client", "gen_cfg", "new_peer"]) + .help("Runs the program in certain mode")) + .arg(Arg::with_name("config") + .long("config") + .required(true) + .value_name("FILE") + .help("The path to VPN configuration file") + .takes_value(true)) + .arg(Arg::with_name("peer-cfg") + .long("peer-cfg") + .value_name("FILE") + .help("The path to VPN peer configuration file") + .takes_value(true)) + .arg(Arg::with_name("bind-address") + .long("bind-address") + .value_name("IP:PORT") + .help("The ip:port that would be used to bind server (config)") + .takes_value(true)) + .arg(Arg::with_name("endpoint") + .long("endpoint") + .value_name("IP:PORT") + .help("The ip:port that would be used by client to connect (config)") + .takes_value(true)) + .arg(Arg::with_name("internal-address") + .long("internal-address") + .value_name("IP") + .help("The address of VPN server in it's subnet (config)") + .takes_value(true)) + .arg(Arg::with_name("broadcast-mode") + .long("broadcast-mode") + .help("If set to true, then all incoming traffic with an unknown destination address will be forwarded to all peers (config)") + .takes_value(false)) + .arg(Arg::with_name("grab-endpoint") + .long("grab-endpoint") + .help("If set to true, the endpoint address for peers will be grabbed from server config (config)") + .takes_value(false)) + .arg(Arg::with_name("keepalive") + .long("keepalive") + .required(false) + .value_name("SECONDS") + .default_value("0") + .help("Keepalive packets interval (config)") + .takes_value(true)) + .arg(Arg::with_name("obfs-type") + .long("obfs-type") + .possible_values(&["dns", "veil", "xor"]) + .takes_value(true) + .value_name("OBFS") + .help("Obfuscation protocol (config)")) + .arg(Arg::with_name("interface") + .long("interface") + .required(false) + .takes_value(true) + .value_name("NAME") + .help("Explicitly set network interface name for routing")) + .get_matches(); + + let mode = matches.value_of("mode").unwrap(); + + if let Some(config_path) = matches.value_of("config") { + + let data = fs::read(config_path); + + if data.is_err() { + match mode { + "gen_cfg" => generate_server_config(&matches, config_path), + _ => error!("There is no config file.") + } + return; + } + + let cfg_raw = &String::from_utf8(data.unwrap()).unwrap(); + + match mode { + "server" => init_server(cfg_raw, matches.value_of("interface")).await, + "client" => init_client(cfg_raw, matches.value_of("interface").map_or(None, |x| Some(String::from(x)))).await, + "new_peer" => generate_peer_config(&matches, config_path, cfg_raw), + _ => error!("There is config file already") + } + } } \ No newline at end of file diff --git a/src/obfs.rs b/frida_core/src/obfs.rs similarity index 100% rename from src/obfs.rs rename to frida_core/src/obfs.rs diff --git a/src/server.rs b/frida_core/src/server.rs similarity index 97% rename from src/server.rs rename to frida_core/src/server.rs index 2237a12..af346e8 100644 --- a/src/server.rs +++ b/frida_core/src/server.rs @@ -1,251 +1,251 @@ -use futures::{SinkExt, StreamExt}; -use tokio::sync::mpsc; -use tokio::{net::UdpSocket, sync::Mutex, time}; -use x25519_dalek::{PublicKey, StaticSecret}; -use base64::prelude::*; -use log::{error, info}; -use std::sync::Arc; -use std::net::{ SocketAddr, Ipv4Addr, IpAddr }; -use std::collections::HashMap; -use aes_gcm::{ aead::{Aead, AeadCore, KeyInit, OsRng}, -Aes256Gcm, Nonce }; -use tun::{Configuration, create_as_async}; - -#[cfg(target_os = "linux")] -use network_interface::{NetworkInterface, NetworkInterfaceConfig}; - -use crate::config::{ ServerConfiguration, ServerPeer}; -use crate::udp::{UDPKeepAlive, UDPSerializable, UDPVpnHandshake, UDPVpnPacket}; - -#[cfg(target_os = "linux")] -fn configure_routes(s_interface: Option<&str>) { - let interfaces = NetworkInterface::show().unwrap(); - - let net_inter = interfaces.iter() - .filter(|i| !i.addr.iter().any(|b| b.ip().to_string() == "127.0.0.1" || b.ip().to_string() == "::1") ) - .min_by(|x, y| x.index.cmp(&y.index)) - .unwrap(); - - info!("Main network interface: {:?}", net_inter.name); - - let inter_name = if s_interface.is_some() { s_interface.unwrap() } else { &net_inter.name }; - - let mut ip_output = std::process::Command::new("iptables") - .arg("-A") - .arg("FORWARD") - .arg("-i") - .arg("tun0") - .arg("-o") - .arg(inter_name) - .arg("-j") - .arg("ACCEPT") - .output() - .expect("Failed to execute iptables command."); - - if !ip_output.status.success() { - error!("Failed to forward packets: {:?}", String::from_utf8_lossy(&ip_output.stderr)); - } - - ip_output = std::process::Command::new("iptables") - .arg("-A") - .arg("FORWARD") - .arg("-i") - .arg(inter_name) - .arg("-o") - .arg("tun0") - .arg("-m") - .arg("state") - .arg("--state") - .arg("ESTABLISHED,RELATED") - .arg("-j") - .arg("ACCEPT") - .output() - .expect("Failed to execute iptables command."); - - if !ip_output.status.success() { - error!("Failed to forward packets: {:?}", String::from_utf8_lossy(&ip_output.stderr)); - } - - ip_output = std::process::Command::new("iptables") - .arg("-t") - .arg("nat") - .arg("-A") - .arg("POSTROUTING") - .arg("-o") - .arg(inter_name) - .arg("-j") - .arg("MASQUERADE") - .output() - .expect("Failed to execute iptables command."); - - if !ip_output.status.success() { - error!("Failed to forward packets: {:?}", String::from_utf8_lossy(&ip_output.stderr)); - } -} - -pub async fn server_mode(server_config: ServerConfiguration, s_interface: Option<&str>) { - info!("Starting server..."); - - let mut config = Configuration::default(); - config.address(&server_config.interface.internal_address) - .netmask("255.255.255.0") - .tun_name("tun0") - .up(); - - let dev = create_as_async(&config).unwrap(); - let (mut dev_writer, mut dev_reader) = dev.into_framed().split(); - - let sock = UdpSocket::bind(&server_config.interface.bind_address).await.unwrap(); - let sock_rec = Arc::new(sock); - let sock_hnd = sock_rec.clone(); - let addresses = Arc::new(Mutex::new(HashMap::::new())); - let peers = Arc::new(Mutex::new(Vec::::new())); - - let (send2tun, mut recv2tun) = mpsc::unbounded_channel::>(); // unbounded::>(); - - let (send2hnd, mut recv2hnd) = mpsc::unbounded_channel::<(Vec, SocketAddr)>(); // unbounded::<(Vec, SocketAddr)>(); - - #[cfg(target_os = "linux")] - configure_routes(s_interface); - - let tun_writer_task = tokio::spawn(async move { - loop { - if let Some(bytes) = recv2tun.recv().await { - info!("Sent to tun!"); - let _ = dev_writer.send(bytes).await; - } - } - }); - - let keepalive_sec = server_config.interface.keepalive.clone(); - let send2hnd_cl = send2hnd.clone(); - let addrs_lcl = addresses.clone(); - - let alive_task = tokio::spawn(async move { - let kp_sc = keepalive_sec.clone(); - if kp_sc <= 0 { return; } - loop { - time::sleep(time::Duration::from_secs(kp_sc.into())).await; - let mmp = addrs_lcl.lock().await; - mmp.values().for_each(|p| { - let _ = send2hnd_cl.send((UDPKeepAlive{}.serialize(), p.addr)); - }); - drop(mmp); - } - }); - - let sock_writer_task = tokio::spawn(async move { - loop { - if let Some((handshake, addr)) = recv2hnd.recv().await { - info!("I SENT THAT STUFF"); - let _ = sock_hnd.send_to(&handshake, addr).await; - } - } - }); - - let addrs_cl = addresses.clone(); - let send2hnd_sr = send2hnd.clone(); - let tun_reader_task = tokio::spawn(async move { - while let Some(Ok(buf)) = dev_reader.next().await { - if buf.len() <= 19 { continue; } - - let ip = IpAddr::V4(Ipv4Addr::new(buf[16], buf[17], buf[18], buf[19])); - let mp = addrs_cl.lock().await; - if let Some(peer) = mp.get(&ip) { - let aes = Aes256Gcm::new(&peer.shared_secret.into()); - let nonce = Aes256Gcm::generate_nonce(&mut OsRng); - - let ciphered_data = aes.encrypt(&nonce, &buf[..]); - - if let Ok(ciphered_d) = ciphered_data { - let vpn_packet = UDPVpnPacket{ data: ciphered_d, nonce: nonce.to_vec()}; - let _ = send2hnd_sr.send((vpn_packet.serialize(), peer.addr)); - } else { - error!("Traffic encryption failed."); - } - } else { - // TODO: check in config is broadcast mode enabled (if not, do not send this to everyone) - //mp.values().for_each(| peer | { sock_snd.send_to(&buf[..n], peer.addr); }); - } - drop(mp); - } - }); - - let addrs_lp = addresses.clone(); - let peers_lp = peers.clone(); - - let mut f_plp = peers_lp.lock().await; - server_config.peers.iter().for_each(|c| f_plp.push(c.clone())); - drop(f_plp); - - let send2hnd_ssr = send2hnd.clone(); - - let sock_reader_task = tokio::spawn(async move { - let mut buf = vec![0; 2048]; - loop { - if let Ok((len, addr)) = sock_rec.recv_from(&mut buf).await { - info!("There is packet!"); - let mut mp = addrs_lp.lock().await; - let plp = peers_lp.lock().await; - match buf.first() { - Some(h) => { - match h { - 0 => { - let handshake = UDPVpnHandshake::deserialize(&buf); - info!("Got handshake from {:?}", handshake.request_ip); - let skey = BASE64_STANDARD.encode(&handshake.public_key); - if plp.iter().any(|c| c.ip == handshake.request_ip && c.public_key == skey) { - let internal_ip = IpAddr::V4(handshake.request_ip); - info!("Accepted client"); - let mut k = [0u8; 32]; - for (&x, p) in handshake.public_key.iter().zip(k.iter_mut()) { - *p = x; - } - let static_secret = BASE64_STANDARD.decode(&server_config.interface.private_key).unwrap(); - let mut k1 = [0u8; 32]; - for (&x, p) in static_secret.iter().zip(k1.iter_mut()) { - *p = x; - } - let shared_secret = StaticSecret::from(k1) - .diffie_hellman(&PublicKey::from(k)); - mp.insert(internal_ip, UDPeer { addr, shared_secret: *shared_secret.as_bytes() }); - - let handshake_response = UDPVpnHandshake{ public_key: BASE64_STANDARD.decode(&server_config.interface.public_key).unwrap(), request_ip: handshake.request_ip }; - - let _ = send2hnd_ssr.send((handshake_response.serialize(), addr)); - } else { - info!("Bad handshake"); - //plp.iter().for_each(|c| info!("ip: {:?}; pkey: {:?}", c.ip, c.public_key)); - } - }, // handshake - 1 => { - let packet = UDPVpnPacket::deserialize(&(buf[..len].to_vec())); - mp.values().filter(| p | p.addr == addr).for_each(|p| { - let aes = Aes256Gcm::new(&p.shared_secret.into()); - let nonce = Nonce::clone_from_slice(&packet.nonce[..]); - match aes.decrypt(&nonce, &packet.data[..]) { - Ok(decrypted) => { let _ = send2tun.send(decrypted); }, - Err(error) => error!("Decryption error! {:?}", error) - } - }); - }, // payload - 2 => { }, // got keepalive packet - _ => error!("Unexpected header value.") - } - }, - None => error!("There is no header") - } - drop(plp); - drop(mp); - } - } - }); - - // should be refactored - let _ = tokio::join!(tun_reader_task, sock_reader_task, sock_writer_task, tun_writer_task, alive_task); -} - -struct UDPeer { - addr: SocketAddr, - shared_secret: [u8; 32] +use futures::{SinkExt, StreamExt}; +use tokio::sync::mpsc; +use tokio::{net::UdpSocket, sync::Mutex, time}; +use x25519_dalek::{PublicKey, StaticSecret}; +use base64::prelude::*; +use log::{error, info}; +use std::sync::Arc; +use std::net::{ SocketAddr, Ipv4Addr, IpAddr }; +use std::collections::HashMap; +use aes_gcm::{ aead::{Aead, AeadCore, KeyInit, OsRng}, +Aes256Gcm, Nonce }; +use tun::{Configuration, create_as_async}; + +#[cfg(target_os = "linux")] +use network_interface::{NetworkInterface, NetworkInterfaceConfig}; + +use crate::config::{ ServerConfiguration, ServerPeer}; +use crate::udp::{UDPKeepAlive, UDPSerializable, UDPVpnHandshake, UDPVpnPacket}; + +#[cfg(target_os = "linux")] +fn configure_routes(s_interface: Option<&str>) { + let interfaces = NetworkInterface::show().unwrap(); + + let net_inter = interfaces.iter() + .filter(|i| !i.addr.iter().any(|b| b.ip().to_string() == "127.0.0.1" || b.ip().to_string() == "::1") ) + .min_by(|x, y| x.index.cmp(&y.index)) + .unwrap(); + + info!("Main network interface: {:?}", net_inter.name); + + let inter_name = if s_interface.is_some() { s_interface.unwrap() } else { &net_inter.name }; + + let mut ip_output = std::process::Command::new("iptables") + .arg("-A") + .arg("FORWARD") + .arg("-i") + .arg("tun0") + .arg("-o") + .arg(inter_name) + .arg("-j") + .arg("ACCEPT") + .output() + .expect("Failed to execute iptables command."); + + if !ip_output.status.success() { + error!("Failed to forward packets: {:?}", String::from_utf8_lossy(&ip_output.stderr)); + } + + ip_output = std::process::Command::new("iptables") + .arg("-A") + .arg("FORWARD") + .arg("-i") + .arg(inter_name) + .arg("-o") + .arg("tun0") + .arg("-m") + .arg("state") + .arg("--state") + .arg("ESTABLISHED,RELATED") + .arg("-j") + .arg("ACCEPT") + .output() + .expect("Failed to execute iptables command."); + + if !ip_output.status.success() { + error!("Failed to forward packets: {:?}", String::from_utf8_lossy(&ip_output.stderr)); + } + + ip_output = std::process::Command::new("iptables") + .arg("-t") + .arg("nat") + .arg("-A") + .arg("POSTROUTING") + .arg("-o") + .arg(inter_name) + .arg("-j") + .arg("MASQUERADE") + .output() + .expect("Failed to execute iptables command."); + + if !ip_output.status.success() { + error!("Failed to forward packets: {:?}", String::from_utf8_lossy(&ip_output.stderr)); + } +} + +pub async fn server_mode(server_config: ServerConfiguration, s_interface: Option<&str>) { + info!("Starting server..."); + + let mut config = Configuration::default(); + config.address(&server_config.interface.internal_address) + .netmask("255.255.255.0") + .tun_name("tun0") + .up(); + + let dev = create_as_async(&config).unwrap(); + let (mut dev_writer, mut dev_reader) = dev.into_framed().split(); + + let sock = UdpSocket::bind(&server_config.interface.bind_address).await.unwrap(); + let sock_rec = Arc::new(sock); + let sock_hnd = sock_rec.clone(); + let addresses = Arc::new(Mutex::new(HashMap::::new())); + let peers = Arc::new(Mutex::new(Vec::::new())); + + let (send2tun, mut recv2tun) = mpsc::unbounded_channel::>(); // unbounded::>(); + + let (send2hnd, mut recv2hnd) = mpsc::unbounded_channel::<(Vec, SocketAddr)>(); // unbounded::<(Vec, SocketAddr)>(); + + #[cfg(target_os = "linux")] + configure_routes(s_interface); + + let tun_writer_task = tokio::spawn(async move { + loop { + if let Some(bytes) = recv2tun.recv().await { + info!("Sent to tun!"); + let _ = dev_writer.send(bytes).await; + } + } + }); + + let keepalive_sec = server_config.interface.keepalive.clone(); + let send2hnd_cl = send2hnd.clone(); + let addrs_lcl = addresses.clone(); + + let alive_task = tokio::spawn(async move { + let kp_sc = keepalive_sec.clone(); + if kp_sc <= 0 { return; } + loop { + time::sleep(time::Duration::from_secs(kp_sc.into())).await; + let mmp = addrs_lcl.lock().await; + mmp.values().for_each(|p| { + let _ = send2hnd_cl.send((UDPKeepAlive{}.serialize(), p.addr)); + }); + drop(mmp); + } + }); + + let sock_writer_task = tokio::spawn(async move { + loop { + if let Some((handshake, addr)) = recv2hnd.recv().await { + info!("I SENT THAT STUFF"); + let _ = sock_hnd.send_to(&handshake, addr).await; + } + } + }); + + let addrs_cl = addresses.clone(); + let send2hnd_sr = send2hnd.clone(); + let tun_reader_task = tokio::spawn(async move { + while let Some(Ok(buf)) = dev_reader.next().await { + if buf.len() <= 19 { continue; } + + let ip = IpAddr::V4(Ipv4Addr::new(buf[16], buf[17], buf[18], buf[19])); + let mp = addrs_cl.lock().await; + if let Some(peer) = mp.get(&ip) { + let aes = Aes256Gcm::new(&peer.shared_secret.into()); + let nonce = Aes256Gcm::generate_nonce(&mut OsRng); + + let ciphered_data = aes.encrypt(&nonce, &buf[..]); + + if let Ok(ciphered_d) = ciphered_data { + let vpn_packet = UDPVpnPacket{ data: ciphered_d, nonce: nonce.to_vec()}; + let _ = send2hnd_sr.send((vpn_packet.serialize(), peer.addr)); + } else { + error!("Traffic encryption failed."); + } + } else { + // TODO: check in config is broadcast mode enabled (if not, do not send this to everyone) + //mp.values().for_each(| peer | { sock_snd.send_to(&buf[..n], peer.addr); }); + } + drop(mp); + } + }); + + let addrs_lp = addresses.clone(); + let peers_lp = peers.clone(); + + let mut f_plp = peers_lp.lock().await; + server_config.peers.iter().for_each(|c| f_plp.push(c.clone())); + drop(f_plp); + + let send2hnd_ssr = send2hnd.clone(); + + let sock_reader_task = tokio::spawn(async move { + let mut buf = vec![0; 2048]; + loop { + if let Ok((len, addr)) = sock_rec.recv_from(&mut buf).await { + info!("There is packet!"); + let mut mp = addrs_lp.lock().await; + let plp = peers_lp.lock().await; + match buf.first() { + Some(h) => { + match h { + 0 => { + let handshake = UDPVpnHandshake::deserialize(&buf); + info!("Got handshake from {:?}", handshake.request_ip); + let skey = BASE64_STANDARD.encode(&handshake.public_key); + if plp.iter().any(|c| c.ip == handshake.request_ip && c.public_key == skey) { + let internal_ip = IpAddr::V4(handshake.request_ip); + info!("Accepted client"); + let mut k = [0u8; 32]; + for (&x, p) in handshake.public_key.iter().zip(k.iter_mut()) { + *p = x; + } + let static_secret = BASE64_STANDARD.decode(&server_config.interface.private_key).unwrap(); + let mut k1 = [0u8; 32]; + for (&x, p) in static_secret.iter().zip(k1.iter_mut()) { + *p = x; + } + let shared_secret = StaticSecret::from(k1) + .diffie_hellman(&PublicKey::from(k)); + mp.insert(internal_ip, UDPeer { addr, shared_secret: *shared_secret.as_bytes() }); + + let handshake_response = UDPVpnHandshake{ public_key: BASE64_STANDARD.decode(&server_config.interface.public_key).unwrap(), request_ip: handshake.request_ip }; + + let _ = send2hnd_ssr.send((handshake_response.serialize(), addr)); + } else { + info!("Bad handshake"); + //plp.iter().for_each(|c| info!("ip: {:?}; pkey: {:?}", c.ip, c.public_key)); + } + }, // handshake + 1 => { + let packet = UDPVpnPacket::deserialize(&(buf[..len].to_vec())); + mp.values().filter(| p | p.addr == addr).for_each(|p| { + let aes = Aes256Gcm::new(&p.shared_secret.into()); + let nonce = Nonce::clone_from_slice(&packet.nonce[..]); + match aes.decrypt(&nonce, &packet.data[..]) { + Ok(decrypted) => { let _ = send2tun.send(decrypted); }, + Err(error) => error!("Decryption error! {:?}", error) + } + }); + }, // payload + 2 => { }, // got keepalive packet + _ => error!("Unexpected header value.") + } + }, + None => error!("There is no header") + } + drop(plp); + drop(mp); + } + } + }); + + // should be refactored + let _ = tokio::join!(tun_reader_task, sock_reader_task, sock_writer_task, tun_writer_task, alive_task); +} + +struct UDPeer { + addr: SocketAddr, + shared_secret: [u8; 32] } \ No newline at end of file diff --git a/src/udp.rs b/frida_core/src/udp.rs similarity index 100% rename from src/udp.rs rename to frida_core/src/udp.rs diff --git a/tray.rc b/frida_core/tray.rc similarity index 100% rename from tray.rc rename to frida_core/tray.rc