├── .clang-format ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── LICENSE ├── README.adoc ├── certs ├── server.key └── shared.crt ├── docker-compose-dev.yml ├── docker-compose-run.yml ├── docker-compose.yml ├── docker └── Dockerfile ├── include └── lw.h ├── iperf_docker └── Dockerfile ├── project.yml ├── scripts ├── run_iperf_client.sh ├── run_server.sh └── setup_nat_tun.sh ├── src ├── he │ ├── helium.c │ └── helium.h ├── main.c ├── state.c ├── state.h ├── tun │ ├── tun.c │ ├── tun.h │ ├── tun_network.c │ ├── tun_network.h │ ├── tun_util.c │ └── tun_util.h ├── udp │ ├── client.c │ ├── client.h │ ├── flow.c │ ├── flow.h │ ├── server.c │ └── server.h ├── util.c └── util.h └── test ├── support ├── libhe_testable_types.h └── test_defs.h └── test_util.c /.clang-format: -------------------------------------------------------------------------------- 1 | # Google was the closest style to what was currently being used 2 | BasedOnStyle: Google 3 | # SortIncludes can be re-enabled after tidying up various includes 4 | # but to avoid breaking stuff, leaving it disabled for now 5 | SortIncludes: false 6 | # Because 80 characters just doesn't make sense on a 4K screen and 7 | # the Linux kernel uses 100 8 | ColumnLimit: 100 9 | # Personal preference 10 | DerivePointerAlignment: false 11 | PointerAlignment: Right 12 | SpaceBeforeParens: Never 13 | # Be consistent in all function definitions 14 | AllowShortFunctionsOnASingleLine: false 15 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # .github/workflows/ci.yml 2 | name: CI 3 | on: 4 | push: 5 | branches: 6 | - "**" 7 | pull_request: 8 | branches: [main] 9 | jobs: 10 | linux: 11 | runs-on: ubuntu-22.04 12 | steps: 13 | - uses: actions/checkout@v3 14 | - name: Install Ceedling 15 | run: sudo gem install ceedling --no-user-install 16 | - name: Clobber project 17 | run: ceedling clobber 18 | - name: Fetch dependencies 19 | run: ceedling dependencies:fetch 20 | - name: Build dependencies 21 | run: ceedling dependencies:make 22 | - name: Build laser 23 | run: ceedling release 24 | docker: 25 | runs-on: ubuntu-22.04 26 | steps: 27 | - uses: actions/checkout@v3 28 | - name: Run docker build 29 | run: docker build -f docker/Dockerfile . 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | third_party/ 3 | debian/.debhelper/ 4 | 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | //// 2 | Lightway Laser 3 | Copyright (C) 2021 Express VPN International Ltd. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | //// 19 | = Lightway Laser - Lightway Reference Client/Server 20 | 21 | This is an intentionally limited reference client/server application that creates a point-to-point 22 | private connection between two Linux machines using https://github.com/expressvpn/lightway-core[Lightway Core]. 23 | 24 | == Spin It All Up in Docker and Run an Integration Test 25 | 26 | [source,bash] 27 | docker compose -f docker-compose.yml -f docker-compose-run.yml up --exit-code-from cli 28 | 29 | == Spin Up Interactive Docker Containers for Live Builds 30 | 31 | [source,bash] 32 | docker compose -f docker-compose.yml -f docker-compose-dev.yml up 33 | # In another terminal 34 | docker compose exec server /bin/bash 35 | # In yet another terminal 36 | docker compose exec cli /bin/bash 37 | 38 | == Build and Run Client/Server 39 | 40 | . Install ceedling 41 | + 42 | [source,bash] 43 | gem install ceedling 44 | 45 | . Setup the network (server-only) 46 | + 47 | [source,bash] 48 | scripts/setup_nat_tun.sh 49 | 50 | . Build binary 51 | + 52 | [source,bash] 53 | ceedling release 54 | 55 | . Start server 56 | + 57 | [source,bash] 58 | scripts/run_server.sh 59 | 60 | . Start client (on a different machine or container) 61 | + 62 | [source,bash] 63 | scripts/run_iperf_client.sh 64 | 65 | 66 | -------------------------------------------------------------------------------- /certs/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCrWN/eREd5swtS 3 | 9M69hfCvWc0qSp1jQ9eXPFFXyy66nSBYFP2Ajsr50hJd1WzWfyeVF3DZj2gepHq3 4 | vsvJVHP8xFj0+pNHtGUZFeFfT8du758MTJ67Cd3pvkUcgkxfflWHVSvGvdk+1a8h 5 | humiyW0yV3ZIhbx99DZshiFxlIUs+MmsbQ3mBctBSrChFrqMIjKIRdt0CsTyPhtv 6 | ehzZJLvzmqW0qzE28+y0U7sT2ZOiP5zCvoKdFrx3t6UlTFKttBgpYZ/43Zsvw09s 7 | QCwZxDuAyf+M0YPFcnzTDNvY1WLd0phB4D8GRsCZtRxHNdFvWtrRVncgBXBcu1Ip 8 | A2nnMJx1AgMBAAECggEAEVmScYMgaaZDg0bemDozwM2rBJlBjoeUEPA+nFEqjiLS 9 | 35hggt/ylZE74tx1hNKjQ2l4N89Zj6C//FMJd31hsTqAd23X8+7EPeIFTA1b+FOz 10 | Gx+3AuFg4wYtIVHgQdsc9fMd16XplX81mIN8rMsQj4RjqbxA9dAAosSCJmoPghoU 11 | eKvNWdFUD/mpIVv2pnD1OKYoy+Zdre5EnAALMmOQ5hiXkfsPDVxU6gNhtrnT8rVL 12 | pMnyEeruCqYmRB4uC5bmamOq3/8xLukQ5T909TXLzHHvueCxMvf5fD0IERHlfo7/ 13 | QUmzDrw/Fr9GKJlIlOh/f2SZEIL5uNx3ddt+IyhFEQKBgQDcseERSoMOMeM4L+Tj 14 | nSByZw9M5TTebdfnA/5Vfbs+gd8XXiywwM2oLu/0GAY0uyfWxUieTYz0JT2fSNsz 15 | wb+5Yw4ZUJpuRU09WKw1zctMPMoeyFzC3t05WLXC1knkQcHnZx5gZ4YNsh7sA/Zs 16 | iYJQ8CXmBYJT1YdYCELrywf/cwKBgQDGwg8SdPv0GTaqefK5/CNnL276ftHT1ZF3 17 | xAg7TeFqjenwYTHFHPtvoyj+6rcHY2sqDocQctYq3YCfd1oLkJESV3OS3Fbhr5UY 18 | KNvwj8MyJk4bQgxSRg45mAZhw1tAQDtdXKY8HXfLUwyp3R21hG9InF0lCzvjcJbg 19 | k8DNKzAqdwKBgQC/63BuOP3/OiL+mafSyLGOy1Di7fAr/hnjK/XhIpXSpd371EnI 20 | 6+Hsf+TrwHilIpxiiO29vHL3XetYuWLmf3bbIOkB2rZxbpLc5l/b6jsA8VxTqKoC 21 | TQzU8fAen3tipEybj3E7JMvO3TdGx6tkd7B78lsCzYeon+gzBfwsUUODQQKBgCPA 22 | 0s9CJfSB+Jhv+V7FYWT1XmRHHd2aRGGj7MsmNk9hmdx4z2giz4QEeKJqfGQi2Ssm 23 | k9s8nRP25mVJJfSAm+gNvSeE5UgRuqMu7ml2oulJhLFYjzjZi0OG+lbpumdzZnpj 24 | 6S9VKbB0jwmbUfXODeqk3giE3dAK98kMKxl9FFv/AoGBALDANkML92pMO0M0bjth 25 | KpaK6wfwbQe9FETvxdTxBXrQOS7qrh5r1520o/KVeLZ17Zl2R/8JwRW4w/49Yg9t 26 | gc3cNCYTpeT3EyR4NrFBSd+5o/6oExoyrhOO5d61Rdp372mdEKfveVufMRpSsFZa 27 | N1BHD4UmvzkTBJyEnomCsmkE 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /certs/shared.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDjzCCAnegAwIBAgIUHB34aYMvdw7cfOu6wXW1WlxQtrswDQYJKoZIhvcNAQEL 3 | BQAwVzELMAkGA1UEBhMCVVMxDzANBgNVBAgMBkRlbmlhbDEUMBIGA1UEBwwLU3By 4 | aW5nZmllbGQxDDAKBgNVBAoMA0RpczETMBEGA1UEAwwKZ29hd2F5LmNvbTAeFw0y 5 | MTA1MjAwODE1MTNaFw0zMTA1MTgwODE1MTNaMFcxCzAJBgNVBAYTAlVTMQ8wDQYD 6 | VQQIDAZEZW5pYWwxFDASBgNVBAcMC1NwcmluZ2ZpZWxkMQwwCgYDVQQKDANEaXMx 7 | EzARBgNVBAMMCmdvYXdheS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK 8 | AoIBAQCrWN/eREd5swtS9M69hfCvWc0qSp1jQ9eXPFFXyy66nSBYFP2Ajsr50hJd 9 | 1WzWfyeVF3DZj2gepHq3vsvJVHP8xFj0+pNHtGUZFeFfT8du758MTJ67Cd3pvkUc 10 | gkxfflWHVSvGvdk+1a8hhumiyW0yV3ZIhbx99DZshiFxlIUs+MmsbQ3mBctBSrCh 11 | FrqMIjKIRdt0CsTyPhtvehzZJLvzmqW0qzE28+y0U7sT2ZOiP5zCvoKdFrx3t6Ul 12 | TFKttBgpYZ/43Zsvw09sQCwZxDuAyf+M0YPFcnzTDNvY1WLd0phB4D8GRsCZtRxH 13 | NdFvWtrRVncgBXBcu1IpA2nnMJx1AgMBAAGjUzBRMB0GA1UdDgQWBBTpiK7hbR6O 14 | U8raZ/SQe4Ii18f86TAfBgNVHSMEGDAWgBTpiK7hbR6OU8raZ/SQe4Ii18f86TAP 15 | BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBRXYWTTJ8M+gEMMS2+ 16 | JEDunBMCrmaBQIRNq7fU0vHrWA4j4u+2Zr4siMtueCxsJoJG3mPEdeal/N2T/JG9 17 | ygqw3YMnZyPnAHXujk3tjQT+2zMVUJx+rwy6h1tq+YjpsfmZtga4atvemZ+gZZAP 18 | uT+rmKbSpnRNjUs8QwhqPqoZ5wJwCjxO2gyyMy437J1NY6Ss21bwA9cGuX0qDP9e 19 | QkegMrRH16yWVL3exro58slg7S0PyyDHaUWEcWBB0dmhLRBkYDb9XXl/gxmdBP8O 20 | LsaIhNGjiK5Lt8cTRkZOLYuXvi1/CgW34d1YazAGpUSG2dE6YL2TruV8kRa7AMzV 21 | qTMy 22 | -----END CERTIFICATE----- 23 | -------------------------------------------------------------------------------- /docker-compose-dev.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | networks: 4 | perfnet: 5 | driver: bridge 6 | 7 | services: 8 | server: 9 | tty: true 10 | build: 11 | target: builder 12 | command: sleep infinity 13 | volumes: 14 | - './:/lw_reference' 15 | cli: 16 | tty: true 17 | build: 18 | target: builder 19 | command: sleep infinity 20 | volumes: 21 | - './:/lw_reference' 22 | 23 | -------------------------------------------------------------------------------- /docker-compose-run.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | networks: 4 | perfnet: 5 | driver: bridge 6 | 7 | services: 8 | server: 9 | command: scripts/run_server.sh 10 | cli: 11 | command: scripts/run_iperf_client.sh 12 | 13 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | networks: 4 | perfnet: 5 | driver: bridge 6 | 7 | services: 8 | iperf: 9 | build: iperf_docker 10 | networks: 11 | perfnet: 12 | aliases: 13 | - iperf 14 | server: 15 | build: 16 | context: . 17 | dockerfile: docker/Dockerfile 18 | networks: 19 | - perfnet 20 | cap_add: 21 | - NET_ADMIN 22 | devices: 23 | - "/dev/net/tun:/dev/net/tun" 24 | cli: 25 | build: 26 | context: . 27 | dockerfile: docker/Dockerfile 28 | depends_on: 29 | - iperf 30 | - server 31 | networks: 32 | - perfnet 33 | environment: 34 | - HELIUM_GATE=10.125.0.2 35 | cap_add: 36 | - NET_ADMIN 37 | devices: 38 | - "/dev/net/tun:/dev/net/tun" 39 | 40 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian/buildd:buster as builder 2 | ARG DEBIAN_FRONTEND=noninteractive 3 | 4 | ENV LANG C.UTF-8 5 | ENV LC_ALL C.UTF-8 6 | 7 | RUN apt-get update && apt-get install -qqy --no-install-recommends \ 8 | autoconf \ 9 | automake \ 10 | bsdmainutils \ 11 | dnsutils \ 12 | git \ 13 | iperf3 \ 14 | iproute2 \ 15 | iptables \ 16 | iputils-ping \ 17 | liblua5.3-dev \ 18 | libtool \ 19 | libsqlite3-dev \ 20 | lua5.3 \ 21 | procps \ 22 | psmisc \ 23 | rubygems \ 24 | tcpdump \ 25 | unzip \ 26 | valgrind \ 27 | wget \ 28 | strace \ 29 | vim \ 30 | cmake 31 | 32 | # Set up ceedling 33 | RUN gem install ceedling 34 | 35 | WORKDIR /lw_reference 36 | 37 | FROM builder 38 | COPY ./ . 39 | RUN ceedling clobber 40 | RUN ceedling verbosity[4] dependencies:fetch 41 | RUN ceedling verbosity[4] dependencies:make 42 | RUN ceedling verbosity[4] release 43 | -------------------------------------------------------------------------------- /include/lw.h: -------------------------------------------------------------------------------- 1 | /* * 2 | * Lightway Laser 3 | * Copyright (C) 2021 Express VPN International Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef LW_H 21 | #define LW_H 22 | 23 | #include 24 | #include 25 | 26 | #define LW_MAX_WIRE_MTU 1500 27 | #define LW_MAX_INSIDE_MTU 1350 28 | 29 | typedef struct lw_config { 30 | // Username 31 | char *username; 32 | // Password 33 | char *password; 34 | // Server IP 35 | char *server_ip; 36 | // Server Port 37 | int server_port; 38 | // Streaming Mode 39 | bool streaming; 40 | // Tun device name 41 | char *tun_name; 42 | // Server Cert 43 | char *crt_path; 44 | // Server Key 45 | char *server_key_path; 46 | } lw_config_t; 47 | 48 | typedef struct lw_state { 49 | // Shared uv_loop 50 | uv_loop_t *loop; 51 | 52 | // Mutually exclusive, one or the other will be NULL based on connection_type 53 | uv_udp_t udp_socket; 54 | uv_tcp_t tcp_socket; 55 | 56 | // Connection Information 57 | // UDP Send addr 58 | struct sockaddr_in send_addr; 59 | // UDP Session ID 60 | uint64_t session; 61 | 62 | // Helium Data 63 | he_ssl_ctx_t *he_ctx; 64 | he_conn_t *he_conn; 65 | uv_timer_t he_timer; 66 | 67 | // Homogeneous client IP 68 | // We cache as str and u32 for 69 | // different procedures 70 | char const *client_ip; 71 | uint32_t client_ip_u32; 72 | 73 | // Client's local IP 74 | char const *local_ip; 75 | // Homogenous peer IP 76 | char const *peer_ip; 77 | // Homogenous DNS ip 78 | char const *dns_ip; 79 | int mtu; 80 | 81 | // The external IP viewable to the outside world 82 | uint32_t assigned_ip; 83 | 84 | // Auth pieces 85 | char username[HE_CONFIG_TEXT_FIELD_LENGTH]; 86 | char password[HE_CONFIG_TEXT_FIELD_LENGTH]; 87 | 88 | // Tun FD 89 | int tun_fd; 90 | uv_poll_t uv_tun; 91 | char tun_name[HE_CONFIG_TEXT_FIELD_LENGTH]; 92 | 93 | // Server or not -- most things don't actually care but some do 94 | bool is_server; 95 | 96 | } lw_state_t; 97 | 98 | #endif // LW_H 99 | -------------------------------------------------------------------------------- /iperf_docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:latest 2 | RUN apt-get update --fix-missing && \ 3 | DEBIAN_FRONTEND=noninteractive apt-get install -qqy --no-install-recommends \ 4 | iperf \ 5 | iperf3 \ 6 | iproute2 \ 7 | tcpdump 8 | 9 | CMD ip addr & nice -n 19 iperf3 -i 5 -s 10 | -------------------------------------------------------------------------------- /project.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | :project: 4 | :use_exceptions: FALSE 5 | :use_test_preprocessor: TRUE 6 | :use_auxiliary_dependencies: TRUE 7 | :build_root: build 8 | :release_build: TRUE 9 | :test_file_prefix: test_ 10 | :which_ceedling: gem 11 | :default_tasks: 12 | - test:all 13 | 14 | :release_build: 15 | :output: lw.out 16 | 17 | :environment: 18 | 19 | :extension: 20 | :executable: .out 21 | 22 | :paths: 23 | :source: 24 | - src/** 25 | :test: 26 | - +:test/** 27 | - -:test/support 28 | :include: 29 | - include/* 30 | :support: 31 | - test/support 32 | 33 | :defines: 34 | # in order to add common defines: 35 | # 1) remove the trailing [] from the :common: section 36 | # 2) add entries to the :common: section (e.g. :test: has TEST defined) 37 | :common: &common_defines [] 38 | :test: 39 | - *common_defines 40 | - TEST 41 | :test_preprocess: 42 | - *common_defines 43 | - TEST 44 | 45 | :cmock: 46 | :mock_prefix: mock_ 47 | :when_no_prototypes: :warn 48 | :enforce_strict_ordering: TRUE 49 | :includes: 50 | - libhe_testable_types.h 51 | :plugins: 52 | - :ignore 53 | - :callback 54 | - :expect_any_args 55 | - :ignore_arg 56 | :treat_as: 57 | uint8: HEX8 58 | uint16: HEX16 59 | uint32: UINT32 60 | int8: INT8 61 | bool: UINT8 62 | 63 | 64 | :plugins: 65 | :load_paths: 66 | - "#{Ceedling.load_path}" 67 | :enabled: 68 | - module_generator 69 | - dependencies 70 | - compile_commands_json 71 | 72 | :dependencies: 73 | :libraries: 74 | - :name: lightway_core 75 | :source_path: third_party/lightway_core 76 | :fetch: 77 | :method: :git 78 | :source: https://github.com/expressvpn/lightway-core.git 79 | :branch: main 80 | :environment: 81 | - CFLAGS= -DLARGE_STATIC_BUFFERS -DWOLFSSL_DTLS_ALLOW_FUTURE -DWOLFSSL_MIN_RSA_BITS=2048 -DWOLFSSL_MIN_ECC_BITS=256 -fPIC 82 | :build: 83 | - /usr/local/bin/ceedling verbosity[4] release project:linux 84 | :artifacts: 85 | :includes: 86 | - public/** 87 | :static_libraries: 88 | - build/artifacts/release/libhelium.a 89 | - third_party/builds/wolfssl_build/lib/libwolfssl.a 90 | - third_party/liboqs/build/lib/liboqs.a 91 | - :name: libuv 92 | :source_path: third_party/libuv 93 | :artifact_path: third_party/builds/libuv 94 | :fetch: 95 | :method: :git 96 | :source: https://github.com/libuv/libuv.git 97 | :tag: v1.46.0 98 | :build: 99 | - "sh autogen.sh" 100 | - "./configure --prefix=$(pwd)/../builds/libuv/ --enable-static --disable-shared" 101 | - "make" 102 | - "make install" 103 | :artifacts: 104 | :includes: 105 | - include/* 106 | :static_libraries: 107 | - lib/libuv.a 108 | - :name: zlog 109 | :source_path: third_party/zlog 110 | :artifact_path: third_party/zlog/tidy 111 | :fetch: 112 | :method: :git 113 | :source: https://github.com/zma/zlog.git 114 | :commit: 16f266e 115 | :build: 116 | - mkdir -p tidy 117 | - cp zlog.c tidy/ 118 | - cp zlog.h tidy/ 119 | - cp zlog-config.h tidy/ 120 | - sed -i "s/1 << 22/1 << 10/" tidy/zlog-config.h 121 | - sed -i "s/15/2/" zlog-config.h 122 | :artifacts: 123 | :includes: 124 | - /* 125 | :source: 126 | - /zlog.c 127 | - :name: argparse 128 | :source_path: third_party/argparse 129 | :artifact_path: third_party/argparse/tidy 130 | :fetch: 131 | :method: :git 132 | :source: https://github.com/cofyc/argparse.git 133 | :tag: v1.1.0 134 | :build: 135 | - mkdir -p tidy 136 | - cp argparse.c tidy/ 137 | - cp argparse.h tidy/ 138 | :artifacts: 139 | :includes: 140 | - /* 141 | :source: 142 | - /argparse.c 143 | 144 | 145 | :tools_release_linker: 146 | :arguments: 147 | - -lpthread 148 | - -lm 149 | - -ldl 150 | 151 | :flags: 152 | :release: 153 | :compile: 154 | :*: 155 | - -O3 156 | - -g 157 | 158 | ... 159 | -------------------------------------------------------------------------------- /scripts/run_iperf_client.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | SERVER=$(dig +short server) 6 | TARGET=$(dig +short iperf) 7 | 8 | echo "Resolved to target ${TARGET} server ${SERVER}" 9 | 10 | echo "Check that we have connectivity to the lightway server" 11 | ping -w1 "${SERVER}" 12 | 13 | build/release/lw.out --client --protocol udp --username test --password test --server_ip ${SERVER} --server_port 19655 --cert certs/shared.crt --tun helium-test & 14 | 15 | sleep 2 16 | 17 | echo "Setting route to ${TARGET} via ${HELIUM_GATE}" 18 | ip route add "${TARGET}" via "${HELIUM_GATE}" 19 | 20 | sleep 2 21 | 22 | echo "Route to target" 23 | ip route get ${TARGET} 24 | 25 | echo "Pinging ${TARGET} a little bit to make sure we're routed" 26 | ping -w3 ${TARGET} 27 | 28 | echo "Beginning iperf test" 29 | iperf3 -t 60 -c ${TARGET} 30 | 31 | echo "Beginning iperf reverse test" 32 | iperf3 -t 60 -c ${TARGET} -R 33 | 34 | kill %1 35 | -------------------------------------------------------------------------------- /scripts/run_server.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | scripts/setup_nat_tun.sh 6 | 7 | build/release/lw.out --server \ 8 | --protocol udp \ 9 | --username test \ 10 | --password test \ 11 | --server_ip '0.0.0.0' \ 12 | --server_port 19655 \ 13 | --cert certs/shared.crt \ 14 | --key certs/server.key \ 15 | --tun helium-test 16 | -------------------------------------------------------------------------------- /scripts/setup_nat_tun.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | tunname="helium-test" 4 | subnet="10.125.0.0/16" 5 | wifidev=$(ip route get 8.8.8.8 | grep -P -o 'dev (.*?) ' | cut -d ' ' -f 2) 6 | basenet=$(ip addr show ${wifidev} | grep -P -o "inet (.*?) " | cut -d ' ' -f 2 | cut -d '/' -f 1) 7 | echo "FOUND DEV AND IP ${wifidev} ${basenet}" 8 | gateway=$(ip route get 8.8.8.8 | grep -P -o 'via (.*?) ' | cut -d ' ' -f 2) 9 | echo "FOUND GATEWAY: " ${gateway} 10 | 11 | iptables -P INPUT ACCEPT 12 | iptables -P OUTPUT ACCEPT 13 | iptables -P FORWARD ACCEPT 14 | iptables -t nat -A POSTROUTING -s ${subnet} -o ${wifidev} -j SNAT --to ${basenet} 15 | 16 | ip tuntap add mode tun dev $tunname 17 | ip link set dev $tunname mtu 1350 18 | ip link set dev $tunname up 19 | ip addr replace 10.125.0.1 peer 10.125.0.2 dev $tunname 20 | ip route replace 10.125.0.0/16 via 10.125.0.2 21 | 22 | -------------------------------------------------------------------------------- /src/he/helium.c: -------------------------------------------------------------------------------- 1 | /* * 2 | * Lightway Laser 3 | * Copyright (C) 2021 Express VPN International Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include "helium.h" 21 | 22 | #include "util.h" 23 | #include "state.h" 24 | 25 | bool auth_cb(he_conn_t *he_conn, char const *username, char const *password, void *context) { 26 | lw_state_t *state = (lw_state_t *)context; 27 | 28 | int username_compare = strncmp(state->username, username, sizeof(state->username)); 29 | // Of course we know that auth fails if the password comparison fails, but we want 30 | // to make sure that the same amount of time passes for auth success and failure 31 | int password_compare = strncmp(state->password, password, sizeof(state->password)); 32 | 33 | return (username_compare == 0) && (password_compare == 0); 34 | } 35 | 36 | he_return_code_t populate_network_config_ipv4_cb(he_conn_t *he_conn, 37 | he_network_config_ipv4_t *config, void *context) { 38 | lw_state_t *state = (lw_state_t *)context; 39 | 40 | // Copy the homogonized network configuration into the auth response 41 | strncpy(config->local_ip, state->client_ip, sizeof(config->local_ip)); 42 | strncpy(config->peer_ip, state->peer_ip, sizeof(config->peer_ip)); 43 | strncpy(config->dns_ip, state->dns_ip, sizeof(config->dns_ip)); 44 | config->mtu = LW_MAX_INSIDE_MTU; 45 | 46 | return HE_SUCCESS; 47 | } 48 | 49 | void on_he_nudge(uv_timer_t *timer) { 50 | // Grab connection context 51 | lw_state_t *state = (lw_state_t *)timer->data; 52 | 53 | he_conn_nudge(state->he_conn); 54 | } 55 | 56 | he_return_code_t nudge_time_cb(he_conn_t *client, int timeout, void *context) { 57 | // Get our context back 58 | lw_state_t *state = (lw_state_t *)context; 59 | 60 | // Schedule new timeout 61 | int res = uv_timer_start(&state->he_timer, on_he_nudge, (u_int64_t)timeout, 0); 62 | if(res < 0) { 63 | zlogf_time(ZLOG_INFO_LOG_MSG, "Error occurred during uv_timer_start: %s\n", uv_strerror(res)); 64 | return HE_ERR_CALLBACK_FAILED; 65 | } 66 | zlogf_time(ZLOG_INFO_LOG_MSG, "Scheduling Helium nudge in %ld ms\n", timeout); 67 | return HE_SUCCESS; 68 | } 69 | 70 | he_return_code_t server_event_cb(he_conn_t *client, he_conn_event_t event, void *context) { 71 | zlogf_time(ZLOG_INFO_LOG_MSG, "Event occurred %s\n", he_client_event_name(event)); 72 | 73 | return HE_SUCCESS; 74 | } 75 | 76 | he_return_code_t state_change_cb(he_conn_t *client, he_conn_state_t new_state, void *context) { 77 | // Get our context back 78 | lw_state_t *state = (lw_state_t *)context; 79 | 80 | zlogf_time(ZLOG_INFO_LOG_MSG, "State changed to %s\n", he_client_state_name(new_state)); 81 | 82 | if(new_state == HE_STATE_DISCONNECTED) { 83 | zlogf_time(ZLOG_INFO_LOG_MSG, "Helium connection was disconnected\n"); 84 | lw_state_post_disconnect_cleanup(state); 85 | } 86 | 87 | return HE_SUCCESS; 88 | } 89 | 90 | void configure_helium_shared(lw_config_t *config, lw_state_t *state) { 91 | // Return code holder for the various functions 92 | // Note that if we get anything besides success here we just die, no cleanup 93 | int res = 0; 94 | 95 | // Initialise libhelium 96 | res = he_init(); 97 | LW_CHECK_WITH_MSG(res == HE_SUCCESS, "Failed to initialise libhelium"); 98 | 99 | state->he_ctx = he_ssl_ctx_create(); 100 | LW_CHECK_WITH_MSG(state->he_ctx, "Failed to create SSL context"); 101 | 102 | if(config->streaming) { 103 | res = he_ssl_ctx_set_connection_type(state->he_ctx, HE_CONNECTION_TYPE_STREAM); 104 | } else { 105 | res = he_ssl_ctx_set_connection_type(state->he_ctx, HE_CONNECTION_TYPE_DATAGRAM); 106 | } 107 | LW_CHECK_WITH_MSG(res == HE_SUCCESS, "Failed to set the connection type"); 108 | he_ssl_ctx_set_nudge_time_cb(state->he_ctx, nudge_time_cb); 109 | 110 | he_ssl_ctx_set_event_cb(state->he_ctx, server_event_cb); 111 | 112 | he_ssl_ctx_set_state_change_cb(state->he_ctx, state_change_cb); 113 | 114 | res = uv_timer_init(state->loop, &state->he_timer); 115 | LW_CHECK_WITH_MSG(res == 0, "Failed to initialise the Helium timer"); 116 | state->he_timer.data = state; 117 | } 118 | 119 | void configure_helium_server(lw_config_t *config, lw_state_t *state) { 120 | zlogf_time(ZLOG_INFO_LOG_MSG, "Configuring Helium Server...\n"); 121 | 122 | configure_helium_shared(config, state); 123 | 124 | // Return code holder for the various functions 125 | // Note that if we get anything besides success here we just die, no cleanup 126 | int res = 0; 127 | 128 | // Initialise libhelium 129 | 130 | res = he_ssl_ctx_set_server_cert_key_files(state->he_ctx, config->crt_path, 131 | config->server_key_path); 132 | LW_CHECK_WITH_MSG(res == HE_SUCCESS, "Failed to set the server key path"); 133 | 134 | he_ssl_ctx_set_auth_cb(state->he_ctx, auth_cb); 135 | he_ssl_ctx_set_populate_network_config_ipv4_cb(state->he_ctx, populate_network_config_ipv4_cb); 136 | 137 | return; 138 | } 139 | 140 | void start_helium_server(lw_state_t *state) { 141 | // Easy! 142 | int res = he_ssl_ctx_start_server(state->he_ctx); 143 | LW_CHECK_WITH_MSG(res == HE_SUCCESS, "Failed to start the server context"); 144 | } 145 | 146 | void start_helium_server_connection(lw_state_t *state) { 147 | state->he_conn = he_conn_create(); 148 | LW_CHECK_WITH_MSG(state->he_conn, "Unable to allocate new Helium connection"); 149 | 150 | int res = he_conn_set_outside_mtu(state->he_conn, LW_MAX_WIRE_MTU); 151 | LW_CHECK_WITH_MSG(res == HE_SUCCESS, "Unable to set outside MTU"); 152 | 153 | res = he_conn_set_context(state->he_conn, state); 154 | LW_CHECK_WITH_MSG(res == HE_SUCCESS, "Unable to set context"); 155 | 156 | res = he_conn_server_connect(state->he_conn, state->he_ctx, NULL, NULL); 157 | LW_CHECK_WITH_MSG(res == HE_SUCCESS, "Helium connect failed"); 158 | } 159 | 160 | void configure_helium_client(lw_config_t *config, lw_state_t *state) { 161 | zlogf_time(ZLOG_INFO_LOG_MSG, "Configuring Helium client...\n"); 162 | configure_helium_shared(config, state); 163 | 164 | // Return code holder for the various functions 165 | // Note that if we get anything besides success here we just die, no cleanup 166 | int res = 0; 167 | 168 | char *ca_buf = NULL; 169 | size_t length = slurp_file(config->crt_path, &ca_buf); 170 | LW_CHECK_WITH_MSG(length > 0, "Unable to slurp certificate file"); 171 | res = he_ssl_ctx_set_ca(state->he_ctx, ca_buf, length); 172 | LW_CHECK_WITH_MSG(res == HE_SUCCESS, "Failed to set the server key path"); 173 | 174 | state->he_conn = he_conn_create(); 175 | LW_CHECK_WITH_MSG(state->he_conn, "Failed to create connection"); 176 | 177 | res = he_conn_set_username(state->he_conn, config->username); 178 | LW_CHECK_WITH_MSG(res == HE_SUCCESS, "Failed to set username"); 179 | 180 | res = he_conn_set_password(state->he_conn, config->password); 181 | LW_CHECK_WITH_MSG(res == HE_SUCCESS, "Failed to set password"); 182 | 183 | res = he_conn_set_outside_mtu(state->he_conn, LW_MAX_WIRE_MTU); 184 | LW_CHECK_WITH_MSG(res == HE_SUCCESS, "Failed to set outside MTU"); 185 | 186 | res = he_conn_set_context(state->he_conn, state); 187 | LW_CHECK_WITH_MSG(res == HE_SUCCESS, "Failed to set the context"); 188 | 189 | return; 190 | } 191 | 192 | void start_helium_client(lw_state_t *state) { 193 | // First we do the client->wolf_ctx setup 194 | int res = he_ssl_ctx_start(state->he_ctx); 195 | LW_CHECK_WITH_MSG(res == HE_SUCCESS, "Failed to start He context!"); 196 | 197 | res = he_conn_client_connect(state->he_conn, state->he_ctx, NULL, NULL); 198 | LW_CHECK_WITH_MSG(res == HE_SUCCESS, "Failed to connect!"); 199 | } 200 | -------------------------------------------------------------------------------- /src/he/helium.h: -------------------------------------------------------------------------------- 1 | /* * 2 | * Lightway Laser 3 | * Copyright (C) 2021 Express VPN International Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef LW_HELIUM_H 21 | #define LW_HELIUM_H 22 | 23 | #include 24 | 25 | void configure_helium_server(lw_config_t *config, lw_state_t *state); 26 | void start_helium_server(lw_state_t *state); 27 | void start_helium_server_connection(lw_state_t *state); 28 | 29 | void configure_helium_client(lw_config_t *config, lw_state_t *state); 30 | void start_helium_client(lw_state_t *state); 31 | 32 | #endif // LW_HELIUM_H 33 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | /* * 2 | * Lightway Laser 3 | * Copyright (C) 2021 Express VPN International Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | static const char *const usage[] = { 27 | "he.out [--server|--client] [options]", 28 | NULL, 29 | }; 30 | 31 | int main(int argc, const char **argv) { 32 | // Initialise logging 33 | zlog_init_stdout(); 34 | // Flush logs every second 35 | zlog_init_flush_thread_with_interval(1); 36 | atexit(zlog_finish); 37 | 38 | int server = 0; 39 | int client = 0; 40 | 41 | lw_config_t config = {0}; 42 | 43 | const char *protocol = NULL; 44 | 45 | struct argparse_option options[] = { 46 | OPT_HELP(), 47 | OPT_GROUP("Mode options (Mutually Exclusive)"), 48 | OPT_BOOLEAN(0, "server", &server, "server mode"), 49 | OPT_BOOLEAN(0, "client", &client, "client mode"), 50 | OPT_GROUP("Configuration Options"), 51 | OPT_STRING(0, "username", &config.username, "username"), 52 | OPT_STRING(0, "password", &config.password, "password"), 53 | OPT_STRING(0, "server_ip", &config.server_ip, "server ip"), 54 | OPT_INTEGER(0, "server_port", &config.server_port, "server port"), 55 | OPT_STRING(0, "protocol", &protocol, "[udp|tcp]"), 56 | OPT_STRING(0, "cert", &config.crt_path, "path to cert"), 57 | OPT_STRING(0, "key", &config.server_key_path, "path to server key"), 58 | OPT_STRING(0, "tun", &config.tun_name, "tun device to use"), 59 | OPT_END(), 60 | }; 61 | 62 | struct argparse argparse; 63 | argparse_init(&argparse, options, usage, 0); 64 | argparse_describe(&argparse, "\nReference client/server for lightway-core.", ""); 65 | argc = argparse_parse(&argparse, argc, argv); 66 | 67 | LW_CHECK_WITH_MSG((!server || !client), "Choose either --server or --client, not both."); 68 | LW_CHECK_WITH_MSG(server || client, "One of --server or --client is required."); 69 | 70 | if(protocol == NULL) { 71 | zlogf_time(ZLOG_INFO_LOG_MSG, "--protocol is required.\n"); 72 | zlog_finish(); 73 | LW_EXIT_WITH_FAILURE(); 74 | 75 | } else if(0 == strncmp(protocol, "tcp", 3)) { 76 | config.streaming = true; 77 | } else if(0 == strncmp(protocol, "udp", 3)) { 78 | config.streaming = false; 79 | } else { 80 | zlogf_time(ZLOG_INFO_LOG_MSG, "Invalid protocol %s must be either udp or tcp\n", protocol); 81 | zlog_finish(); 82 | LW_EXIT_WITH_FAILURE(); 83 | } 84 | 85 | lw_state_t *state = NULL; 86 | 87 | if(server) { 88 | state = lw_start_server(&config); 89 | } else { 90 | state = lw_start_client(&config); 91 | } 92 | 93 | // Technically unnecessary since we would have exited at this point if there was a problem, but 94 | // always good to double-check 95 | LW_CHECK_WITH_MSG(state, "State returned was null"); 96 | 97 | // Ignore sig pipe (shouldn't affect UDP but adding it now so when TCP is added this isn't 98 | // forgotten) 99 | signal(SIGPIPE, SIG_IGN); 100 | 101 | // Run the main loop 102 | return uv_run(state->loop, UV_RUN_DEFAULT); 103 | 104 | return 0; 105 | } 106 | -------------------------------------------------------------------------------- /src/state.c: -------------------------------------------------------------------------------- 1 | /* * 2 | * Lightway Laser 3 | * Copyright (C) 2021 Express VPN International Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include "state.h" 21 | 22 | #include "util.h" 23 | #include "he/helium.h" 24 | #include "udp/server.h" 25 | #include "udp/client.h" 26 | #include "tun/tun.h" 27 | 28 | lw_state_t *lw_start_server(lw_config_t *config) { 29 | zlogf_time(ZLOG_INFO_LOG_MSG, "Starting server...\n"); 30 | 31 | zlogf_time(ZLOG_INFO_LOG_MSG, "Listening on: %s:%d\n", config->server_ip, 32 | config->server_port); 33 | zlogf_time(ZLOG_INFO_LOG_MSG, "Username: %s\n", config->username); 34 | 35 | zlogf_time(ZLOG_INFO_LOG_MSG, "Server cert: %s\n", config->crt_path); 36 | zlogf_time(ZLOG_INFO_LOG_MSG, "Server key: %s\n", config->server_key_path); 37 | zlogf_time(ZLOG_INFO_LOG_MSG, "Streaming Mode: %s\n", config->streaming ? "true" : "false"); 38 | zlogf_time(ZLOG_INFO_LOG_MSG, "Tun device: %s\n", config->tun_name); 39 | zlog_flush_buffer(); 40 | 41 | // Call sequence is Configure, then start, for helium -> UDP/TCP -> Tunnel 42 | lw_state_t *state = calloc(1, sizeof(lw_state_t)); 43 | LW_CHECK_WITH_MSG(state, "Unable to allocate state"); 44 | 45 | state->is_server = true; 46 | 47 | // Copy the username and password as-is 48 | // strnlen returns min(index offirst null terminator, HE_CONFIG_TEXT_FIELD_LENGTH), won't run to 49 | // infinity 50 | strncpy(state->username, config->username, sizeof(state->username)); 51 | state->username[HE_CONFIG_TEXT_FIELD_LENGTH - 1] = '\0'; 52 | strncpy(state->password, config->password, sizeof(state->password)); 53 | state->password[HE_CONFIG_TEXT_FIELD_LENGTH - 1] = '\0'; 54 | 55 | // Also copy the tun_name as-is 56 | strncpy(state->tun_name, config->tun_name, sizeof(state->tun_name)); 57 | 58 | // Initialise these w/ hardcoded values for now 59 | state->peer_ip = "10.125.0.1"; 60 | state->client_ip = "10.125.0.2"; 61 | state->client_ip_u32 = ip2int("10.125.0.2"); 62 | state->dns_ip = "8.8.8.8"; 63 | 64 | // Initialise libuv 65 | state->loop = uv_default_loop(); 66 | LW_CHECK_WITH_MSG(state->loop, "Unable to obtain default libuv loop"); 67 | 68 | configure_helium_server(config, state); 69 | 70 | if(config->streaming) { 71 | zlogf_time(ZLOG_INFO_LOG_MSG, "Streaming is not supported yet"); 72 | LW_EXIT_WITH_FAILURE(); 73 | } else { 74 | configure_udp_server(config, state); 75 | } 76 | 77 | // Configure Tunnel 78 | configure_tunnel_server(config, state); 79 | 80 | start_helium_server(state); 81 | 82 | if(config->streaming) { 83 | zlogf_time(ZLOG_INFO_LOG_MSG, "Streaming is not supported yet"); 84 | LW_EXIT_WITH_FAILURE(); 85 | } else { 86 | start_udp_server(state); 87 | } 88 | 89 | start_tunnel_server(state); 90 | 91 | return state; 92 | } 93 | 94 | void on_client_kickstart(uv_timer_t *timer) { 95 | lw_state_t *state = (lw_state_t *)timer->data; 96 | 97 | zlogf_time(ZLOG_INFO_LOG_MSG, "Kickstarting client\n"); 98 | 99 | start_helium_client(state); 100 | 101 | start_udp_client(state); 102 | 103 | // We don't start the tunnel here, but instead during the network_config callback 104 | } 105 | 106 | lw_state_t *lw_start_client(lw_config_t *config) { 107 | zlogf_time(ZLOG_INFO_LOG_MSG, "Starting client...\n"); 108 | 109 | zlogf_time(ZLOG_INFO_LOG_MSG, "Connecting to: %s:%d\n", config->server_ip, 110 | config->server_port); 111 | zlogf_time(ZLOG_INFO_LOG_MSG, "Username: %s\n", config->username); 112 | zlogf_time(ZLOG_INFO_LOG_MSG, "Client cert: %s\n", config->crt_path); 113 | zlogf_time(ZLOG_INFO_LOG_MSG, "Streaming Mode: %s\n", config->streaming ? "true" : "false"); 114 | zlogf_time(ZLOG_INFO_LOG_MSG, "Tun device: %s\n", config->tun_name); 115 | zlog_flush_buffer(); 116 | 117 | // Call sequence is Configure, then start, for helium -> UDP/TCP -> Tunnel 118 | lw_state_t *state = calloc(1, sizeof(lw_state_t)); 119 | LW_CHECK_WITH_MSG(state, "Unable to allocate state"); 120 | 121 | state->is_server = false; 122 | 123 | // Copy the username and password as-is 124 | // strnlen returns min(index offirst null terminator, HE_CONFIG_TEXT_FIELD_LENGTH), won't run to 125 | // infinity 126 | strncpy(state->username, config->username, sizeof(state->username)); 127 | state->username[HE_CONFIG_TEXT_FIELD_LENGTH - 1] = '\0'; 128 | strncpy(state->password, config->password, sizeof(state->password)); 129 | state->password[HE_CONFIG_TEXT_FIELD_LENGTH - 1] = '\0'; 130 | 131 | // Also copy the tun_name as-is 132 | strncpy(state->tun_name, config->tun_name, sizeof(state->tun_name)); 133 | state->password[HE_CONFIG_TEXT_FIELD_LENGTH - 1] = '\0'; 134 | 135 | // Initialise libuv 136 | state->loop = uv_default_loop(); 137 | LW_CHECK_WITH_MSG(state->loop, "Unable to obtain default libuv loop"); 138 | 139 | configure_helium_client(config, state); 140 | 141 | if(config->streaming) { 142 | zlogf_time(ZLOG_INFO_LOG_MSG, "Streaming is not supported yet"); 143 | LW_EXIT_WITH_FAILURE(); 144 | } else { 145 | configure_udp_client(config, state); 146 | } 147 | 148 | configure_tunnel_client(config, state); 149 | 150 | uv_timer_start(&state->he_timer, on_client_kickstart, 0, 0); 151 | 152 | return state; 153 | } 154 | 155 | void lw_state_post_disconnect_cleanup(lw_state_t *state) { 156 | uv_timer_stop(&state->he_timer); 157 | he_conn_destroy(state->he_conn); 158 | state->he_conn = NULL; 159 | state->session = 0; 160 | state->assigned_ip = 0; 161 | memset(&state->send_addr, 0, sizeof(state->send_addr)); 162 | } 163 | 164 | void lw_state_disconnect(lw_state_t *state) { 165 | zlogf_time(ZLOG_INFO_LOG_MSG, "Closing connection w/ session ID %x\n", state->session); 166 | int res = he_conn_disconnect(state->he_conn); 167 | 168 | // If this is successful we expect to get called by the state change handler, but if it's not we 169 | // esxpect to clean up anyway 170 | if(res != HE_SUCCESS) { 171 | lw_state_post_disconnect_cleanup(state); 172 | } 173 | } 174 | 175 | void lw_state_server_connect(lw_state_t *state, const struct sockaddr *addr) { 176 | start_helium_server_connection(state); 177 | 178 | // Copy the IP address and session 179 | memcpy(&state->send_addr, addr, sizeof(struct sockaddr)); 180 | state->session = he_conn_get_session_id(state->he_conn); 181 | state->assigned_ip = ip2int("10.125.0.42"); 182 | } 183 | -------------------------------------------------------------------------------- /src/state.h: -------------------------------------------------------------------------------- 1 | /* * 2 | * Lightway Laser 3 | * Copyright (C) 2021 Express VPN International Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef LW_STATE_H 21 | #define LW_STATE_H 22 | 23 | #include 24 | 25 | lw_state_t *lw_start_server(lw_config_t *config); 26 | 27 | void lw_state_server_connect(lw_state_t *state, const struct sockaddr *addr); 28 | void lw_state_disconnect(lw_state_t *state); 29 | void lw_state_post_disconnect_cleanup(lw_state_t *state); 30 | 31 | lw_state_t *lw_start_client(lw_config_t *config); 32 | 33 | #endif // LW_STATE_H 34 | -------------------------------------------------------------------------------- /src/tun/tun.c: -------------------------------------------------------------------------------- 1 | /* * 2 | * Lightway Laser 3 | * Copyright (C) 2021 Express VPN International Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include "tun.h" 21 | 22 | #include "tun_network.h" 23 | #include "tun_util.h" 24 | #include "util.h" 25 | 26 | static he_return_code_t tun_write_cb(he_conn_t *he_conn, uint8_t *packet, size_t length, 27 | void *context) { 28 | // Get our context back 29 | lw_state_t *state = (lw_state_t *)context; 30 | 31 | write_to_tun(state->tun_fd, packet, length); 32 | 33 | return HE_SUCCESS; 34 | } 35 | 36 | void on_tun_event(uv_poll_t *handle, int status, int events) { 37 | // Get our state 38 | lw_state_t *state = (lw_state_t *)handle->data; 39 | LW_CHECK_WITH_MSG(state, "State not found on tunnel event"); 40 | 41 | // What event did we get? We only care about it becoming readable... 42 | if((events & UV_READABLE) == UV_READABLE) { 43 | // Loop over all available packets whilst we're here... 44 | while(true) { 45 | // Create sizeof(HE_MAX_MTU) 46 | // Read in IP packet 47 | 48 | // This needs to be set to a well understood and used variable - no magic numbers... 49 | uint8_t msg_content[LW_MAX_INSIDE_MTU] = {0}; 50 | 51 | // Read a packet 52 | int length = read_from_tun(handle->io_watcher.fd, msg_content, LW_MAX_INSIDE_MTU); 53 | 54 | // Would have blocked, so all packets are read - we can stop reading now 55 | if(length == -1) { 56 | return; 57 | } 58 | 59 | // Drop packets which exceed the MTU 60 | if(length > LW_MAX_INSIDE_MTU) { 61 | // Do nothing, just drop it 62 | continue; 63 | } 64 | 65 | switch(he_internal_packet_type(msg_content, length)) { 66 | case HE_PACKET_IP4: { 67 | int res = he_conn_inside_packet_received(state->he_conn, msg_content, length); 68 | if(res != HE_SUCCESS) { 69 | zlogf_time(ZLOG_INFO_LOG_MSG, "Error returned from libhe for tun packets: %d", res); 70 | } 71 | break; // Out of switch, not the while loop 72 | } 73 | case HE_PACKET_IP6: 74 | case HE_BAD_PACKET: 75 | break; // Out of switch, not the while loop 76 | } 77 | } 78 | } 79 | } 80 | 81 | void lw_config_tunnel_internal(lw_state_t *state) { 82 | // Initialise the tun device (the actual device is set up in a Lua helper script, but ideally we 83 | // should do that natively) 84 | char tundev[IFNAMSIZ]; 85 | strncpy(tundev, state->tun_name, IFNAMSIZ - 1); 86 | tundev[IFNAMSIZ - 1] = '\0'; 87 | 88 | state->tun_fd = tun_alloc(tundev, IFF_TUN | IFF_NO_PI); 89 | 90 | if(state->tun_fd == -1) { 91 | zlogf_time(ZLOG_INFO_LOG_MSG, "Fatal Error: Could not allocate tun device '%s'\n", tundev); 92 | zlog_finish(); 93 | LW_EXIT_WITH_FAILURE(); 94 | } 95 | 96 | // Check the tun devices names match - should do but abort if not as the supporting config won't 97 | // be correct 98 | if(strncmp(tundev, state->tun_name, IFNAMSIZ)) { 99 | zlogf_time(ZLOG_INFO_LOG_MSG, 100 | "Fatal Error: tun device should have been %s but was %s instead!\n", state->tun_name, 101 | tundev); 102 | zlog_finish(); 103 | exit(EXIT_FAILURE); 104 | } 105 | 106 | // Set up the libuv polling handler 107 | int res = uv_poll_init(state->loop, &state->uv_tun, state->tun_fd); 108 | 109 | if(res) { 110 | zlogf_time(ZLOG_INFO_LOG_MSG, "Fatal Error: Could not initialise tun interface - %s\n", 111 | uv_strerror(res)); 112 | zlog_finish(); 113 | exit(EXIT_FAILURE); 114 | } 115 | 116 | // Note that we currently do NOT set the internal IPs here, we assume this has been set up 117 | // externally 118 | 119 | // Store state on the tun interface 120 | state->uv_tun.data = state; 121 | he_ssl_ctx_set_inside_write_cb(state->he_ctx, tun_write_cb); 122 | } 123 | 124 | void configure_tunnel_server(lw_config_t *config, lw_state_t *state) { 125 | lw_config_tunnel_internal(state); 126 | } 127 | 128 | void start_tunnel_server(lw_state_t *state) { 129 | // Start listening on the tun interface 130 | uv_poll_start(&state->uv_tun, UV_READABLE, on_tun_event); 131 | } 132 | 133 | he_return_code_t network_config_ipv4_cb(he_conn_t *he_conn, he_network_config_ipv4_t *config, 134 | void *context) { 135 | lw_state_t *state = (lw_state_t *)context; 136 | 137 | zlogf_time(ZLOG_INFO_LOG_MSG, "Received network config Local: %s Peer: %s DNS: %s MTU: %d\n", 138 | config->local_ip, config->peer_ip, config->dns_ip, config->mtu); 139 | 140 | state->client_ip = config->local_ip; 141 | state->peer_ip = config->peer_ip; 142 | state->dns_ip = config->dns_ip; 143 | state->mtu = config->mtu; 144 | 145 | lw_config_tunnel_internal(state); 146 | 147 | tun_set_ip_internal(state->tun_name, state->client_ip, state->peer_ip, config->mtu); 148 | 149 | uv_poll_start(&state->uv_tun, UV_READABLE, on_tun_event); 150 | 151 | return HE_SUCCESS; 152 | } 153 | 154 | void configure_tunnel_client(lw_config_t *config, lw_state_t *state) { 155 | he_ssl_ctx_set_inside_write_cb(state->he_ctx, tun_write_cb); 156 | he_ssl_ctx_set_network_config_ipv4_cb(state->he_ctx, network_config_ipv4_cb); 157 | } 158 | -------------------------------------------------------------------------------- /src/tun/tun.h: -------------------------------------------------------------------------------- 1 | /* * 2 | * Lightway Laser 3 | * Copyright (C) 2021 Express VPN International Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef LW_TUN_H 21 | #define LW_TUN_H 22 | 23 | #include 24 | 25 | void configure_tunnel_server(lw_config_t *config, lw_state_t *state); 26 | void start_tunnel_server(lw_state_t *state); 27 | 28 | void configure_tunnel_client(lw_config_t *config, lw_state_t *state); 29 | // Note that there is no "start" for clients; the tunnel is started during the connection process 30 | 31 | #endif // LW_TUN_H 32 | -------------------------------------------------------------------------------- /src/tun/tun_network.c: -------------------------------------------------------------------------------- 1 | /* * 2 | * Lightway Laser 3 | * Copyright (C) 2021 Express VPN International Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include "tun_network.h" 21 | 22 | // Following header from: 23 | // https://stackoverflow.com/questions/16519846/parse-ip-and-tcp-header-especially-common-tcp-header-optionsof-packets-capture 24 | #pragma pack(1) 25 | typedef struct { 26 | uint8_t ver_ihl; // 4 bits version and 4 bits internet header length 27 | uint8_t tos; 28 | uint16_t total_length; 29 | uint16_t id; 30 | uint16_t flags_fo; // 3 bits flags and 13 bits fragment-offset 31 | uint8_t ttl; 32 | uint8_t protocol; 33 | uint16_t checksum; 34 | uint32_t src_addr; 35 | uint32_t dst_addr; 36 | } ipv4_header_t; 37 | 38 | #pragma pack() 39 | 40 | he_packet_state_t he_internal_packet_type(uint8_t *packet, size_t length) { 41 | // IPv4 is the smallest header for packets we accept 42 | if(length < sizeof(ipv4_header_t)) { 43 | return HE_BAD_PACKET; 44 | } 45 | 46 | // Bits 0-4 of packet contain the IP version 47 | uint8_t proto = packet[0] >> 4; 48 | switch(proto) { 49 | case 4: 50 | return HE_PACKET_IP4; 51 | case 6: 52 | return HE_PACKET_IP6; 53 | default: 54 | return HE_BAD_PACKET; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/tun/tun_network.h: -------------------------------------------------------------------------------- 1 | /* * 2 | * Lightway Laser 3 | * Copyright (C) 2021 Express VPN International Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef LW_TUN_NETWORK_H 21 | #define LW_TUN_NETWORK_H 22 | 23 | #include 24 | 25 | #include 26 | 27 | typedef enum he_packet_state { 28 | HE_BAD_PACKET = 0, 29 | HE_PACKET_IP4 = 1, 30 | HE_PACKET_IP6 = 2 31 | } he_packet_state_t; 32 | 33 | he_packet_state_t he_internal_packet_type(uint8_t *packet, size_t length); 34 | 35 | #endif // LW_TUN_NETWORK_H 36 | -------------------------------------------------------------------------------- /src/tun/tun_util.c: -------------------------------------------------------------------------------- 1 | /* * 2 | * Lightway Laser 3 | * Copyright (C) 2021 Express VPN International Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include "tun_util.h" 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | 35 | #include "util.h" 36 | 37 | int tun_alloc(char *dev, int flags) { 38 | struct ifreq ifr; 39 | int fd, err; 40 | char *clonedev = "/dev/net/tun"; 41 | if((fd = open(clonedev, O_RDWR)) < 0) { 42 | return fd; 43 | } 44 | 45 | memset(&ifr, 0, sizeof(ifr)); 46 | 47 | ifr.ifr_flags = flags; 48 | 49 | if(*dev) { 50 | strncpy(ifr.ifr_name, dev, IFNAMSIZ - 1); 51 | ifr.ifr_name[IFNAMSIZ - 1] = '\0'; 52 | } 53 | 54 | if((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0) { 55 | close(fd); 56 | return err; 57 | } 58 | 59 | strcpy(dev, ifr.ifr_name); 60 | 61 | return fd; 62 | } 63 | 64 | static void internal_tun_set_ip_ioctl(int s, unsigned long req, const char *name, const char *field, 65 | const struct sockaddr_in *addr) { 66 | struct ifreq in_addreq; 67 | memset(&in_addreq, 0, sizeof(in_addreq)); 68 | strncpy(in_addreq.ifr_name, name, sizeof(in_addreq.ifr_name) - 1); 69 | memcpy(&in_addreq.ifr_addr, addr, sizeof(*addr)); 70 | 71 | int res = ioctl(s, req, &in_addreq); 72 | LW_CHECK_WITH_MSG(res >= 0, "Unable to set ip with ioctl"); 73 | } 74 | 75 | static void internal_tun_set_mtu_ioctl(int s, const char *name, const int mtu) { 76 | struct ifreq req = {0}; 77 | strncpy(req.ifr_name, name, sizeof(req.ifr_name) - 1); 78 | req.ifr_ifru.ifru_mtu = mtu; 79 | 80 | int res = ioctl(s, SIOCSIFMTU, &req); 81 | LW_CHECK_WITH_MSG(res >= 0, "Unable to set MTU with ioctl"); 82 | } 83 | 84 | static void internal_tun_set_flags_up(int s, const char *name) { 85 | struct ifreq req = {0}; 86 | strncpy(req.ifr_name, name, sizeof(req.ifr_name) - 1); 87 | 88 | int res = ioctl(s, SIOCGIFFLAGS, &req); 89 | LW_CHECK_WITH_MSG(res >= 0, "Unable to get flags from tunnel"); 90 | 91 | req.ifr_flags |= IFF_UP; 92 | res = ioctl(s, SIOCSIFFLAGS, &req); 93 | LW_CHECK_WITH_MSG(res >= 0, "Unable to set flags on tunnel"); 94 | } 95 | 96 | void tun_set_ip_internal(const char *tun_name, const char *local_ip, const char *peer_ip, 97 | const int mtu) { 98 | // Only support IPv4 for now 99 | const sa_family_t address_family = AF_INET; 100 | int s = socket(address_family, SOCK_DGRAM | SOCK_CLOEXEC, 0); 101 | LW_CHECK_WITH_MSG(s >= 0, "Unable to create socket for configuring tunnel"); 102 | 103 | struct sockaddr_in addr = {0}; 104 | struct sockaddr_in netmask = {0}; 105 | struct sockaddr_in dstaddr = {0}; 106 | 107 | int res = 0; 108 | 109 | // Parse local_ip 110 | addr.sin_family = address_family; 111 | res = inet_aton(local_ip, &addr.sin_addr); 112 | LW_CHECK_WITH_MSG(res == 1, "Invalid local IP"); 113 | 114 | dstaddr.sin_family = address_family; 115 | res = inet_aton(peer_ip, &dstaddr.sin_addr); 116 | LW_CHECK_WITH_MSG(res == 1, "Invalid peer ip"); 117 | 118 | memset(&netmask, 0, sizeof(netmask)); 119 | netmask.sin_family = address_family; 120 | netmask.sin_addr.s_addr = 0xffffffff; 121 | 122 | internal_tun_set_ip_ioctl(s, SIOCSIFADDR, tun_name, "IP", &addr); 123 | internal_tun_set_ip_ioctl(s, SIOCSIFDSTADDR, tun_name, "PEER", &dstaddr); 124 | internal_tun_set_ip_ioctl(s, SIOCSIFNETMASK, tun_name, "NETMASK", &netmask); 125 | internal_tun_set_mtu_ioctl(s, tun_name, mtu); 126 | 127 | internal_tun_set_flags_up(s, tun_name); 128 | 129 | close(s); 130 | } 131 | 132 | void write_to_tun(int tun_fd, uint8_t *buffer, int length) { 133 | // Can't write to tun before it's ready... 134 | if(tun_fd == 0) return; 135 | 136 | // Drop the packet if it exceeds our max MTU 137 | if(length > LW_MAX_INSIDE_MTU) { 138 | zlogf_time(ZLOG_INFO_LOG_MSG, "Packet was dropped since it exceeds max tunnel MTU"); 139 | zlog_flush_buffer(); 140 | return; 141 | } 142 | 143 | if(write(tun_fd, buffer, length) == -1) { 144 | // TODO: Report Err? 145 | zlogf_time(ZLOG_INFO_LOG_MSG, "Error writing to TUN device"); 146 | zlog_flush_buffer(); 147 | } 148 | } 149 | 150 | ssize_t read_from_tun(int tun_fd, void *buf, size_t count) { 151 | return read(tun_fd, buf, count); 152 | } 153 | -------------------------------------------------------------------------------- /src/tun/tun_util.h: -------------------------------------------------------------------------------- 1 | /* * 2 | * Lightway Laser 3 | * Copyright (C) 2021 Express VPN International Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef LW_TUN_UTIL_H 21 | #define LW_TUN_UTIL_H 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | int tun_alloc(char *dev, int flags); 28 | void tun_set_ip_internal(const char *tun_name, const char *local_ip, const char *peer_ip, 29 | const int mtu); 30 | 31 | // A convenience function to abstract away the write system call for testing 32 | void write_to_tun(int tun_fd, uint8_t *buffer, int length); 33 | 34 | // A convenience function to allow us to abstract away the read system call for testing 35 | ssize_t read_from_tun(int tun_fd, void *buf, size_t count); 36 | 37 | #endif // LW_TUN_UTIL_H 38 | -------------------------------------------------------------------------------- /src/udp/client.c: -------------------------------------------------------------------------------- 1 | /* * 2 | * Lightway Laser 3 | * Copyright (C) 2021 Express VPN International Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include "client.h" 21 | #include "flow.h" 22 | #include "util.h" 23 | 24 | void configure_udp_client(lw_config_t *config, lw_state_t *state) { 25 | zlogf_time(ZLOG_INFO_LOG_MSG, "Configuring UDP Client...\n"); 26 | 27 | int res = uv_udp_init(state->loop, &state->udp_socket); 28 | LW_CHECK_WITH_MSG(res == 0, "Unable to initialise UDP socket"); 29 | 30 | res = uv_ip4_addr(config->server_ip, config->server_port, &state->send_addr); 31 | LW_CHECK_WITH_MSG(res == 0, "Invalid IP address or port"); 32 | 33 | int udp_buffer_size = 15 * MEGABYTE; 34 | uv_send_buffer_size((uv_handle_t *)&state->udp_socket, &udp_buffer_size); 35 | uv_recv_buffer_size((uv_handle_t *)&state->udp_socket, &udp_buffer_size); 36 | 37 | state->udp_socket.data = state; 38 | he_ssl_ctx_set_outside_write_cb(state->he_ctx, udp_write_cb); 39 | 40 | return; 41 | } 42 | 43 | void start_udp_client(lw_state_t *state) { 44 | int res = uv_udp_recv_start(&state->udp_socket, alloc_buffer, on_read); 45 | LW_CHECK_WITH_MSG(res == 0, "Unable to start recv on udp socket"); 46 | 47 | return; 48 | } 49 | -------------------------------------------------------------------------------- /src/udp/client.h: -------------------------------------------------------------------------------- 1 | /* * 2 | * Lightway Laser 3 | * Copyright (C) 2021 Express VPN International Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef LW_UDP_CLIENT_H 21 | #define LW_UDP_CLIENT_H 22 | 23 | #include 24 | 25 | void configure_udp_client(lw_config_t *config, lw_state_t *state); 26 | 27 | void start_udp_client(lw_state_t *state); 28 | 29 | #endif // LW_UDP_SERVER_H 30 | -------------------------------------------------------------------------------- /src/udp/flow.c: -------------------------------------------------------------------------------- 1 | /* * 2 | * Lightway Laser 3 | * Copyright (C) 2021 Express VPN International Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include "flow.h" 21 | #include "util.h" 22 | #include "state.h" 23 | 24 | typedef struct send_req { 25 | uv_udp_send_t req; 26 | uv_buf_t buf; 27 | } send_req_t; 28 | 29 | void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { 30 | // Allocate the buffer 31 | buf->base = calloc(1, suggested_size); 32 | LW_CHECK_WITH_MSG(buf->base, "Unable to allocate buffer for incoming data"); 33 | // Set the size 34 | buf->len = suggested_size; 35 | } 36 | 37 | void on_read(uv_udp_t *handle, ssize_t nread, const uv_buf_t *buf, const struct sockaddr *addr, 38 | unsigned flags) { 39 | LW_CHECK_WITH_MSG(handle, "Impossible state occurred, handle was null in on_read!"); 40 | 41 | // Negative reads are socket errors indicating recvmsg failed 42 | if(nread < 0) { 43 | zlogf_time(ZLOG_INFO_LOG_MSG, "Read Error on UDP socket: %s\n", uv_err_name(nread)); 44 | goto cleanup; 45 | } 46 | 47 | if(nread <= sizeof(he_wire_hdr_t)) { 48 | // Noise 49 | goto cleanup; 50 | } 51 | 52 | if(buf == NULL) { 53 | // Should be impossible 54 | goto cleanup; 55 | } 56 | 57 | he_wire_hdr_t *hdr = (he_wire_hdr_t *)buf->base; 58 | if(hdr->he[0] != 'H' || hdr->he[1] != 'e') { 59 | goto cleanup; 60 | } 61 | 62 | uint64_t session = hdr->session; 63 | 64 | lw_state_t *state = (lw_state_t *)handle->data; 65 | 66 | if(state->is_server) { 67 | if(state->he_conn == NULL && session == HE_PACKET_SESSION_EMPTY) { 68 | zlogf_time(ZLOG_INFO_LOG_MSG, "Creating connection\n"); 69 | lw_state_server_connect(state, addr); 70 | zlogf_time(ZLOG_INFO_LOG_MSG, "Created with session %x\n", state->session); 71 | } else if(state->he_conn == NULL && session != HE_PACKET_SESSION_EMPTY) { 72 | zlogf_time(ZLOG_INFO_LOG_MSG, "Rejecting session!!\n"); 73 | he_session_reject(state, addr); 74 | goto cleanup; 75 | } else if(state->he_conn != NULL && session == HE_PACKET_SESSION_EMPTY) { 76 | // TODO Can't reconnect here :-/ 77 | } 78 | 79 | if(state->he_conn == NULL) { 80 | zlogf_time(ZLOG_INFO_LOG_MSG, "Unable to connect"); 81 | goto cleanup; 82 | } 83 | 84 | // We don't support non-IP4 connections here so we'll just cast and assume it works 85 | struct sockaddr_in *addr_in = (struct sockaddr_in *)addr; 86 | 87 | // Check for change of address 88 | if(state->send_addr.sin_addr.s_addr != addr_in->sin_addr.s_addr || 89 | state->send_addr.sin_port != addr_in->sin_port) { 90 | if(session == state->session) { 91 | // Copy in the client's IP address 92 | memcpy(&state->send_addr, addr, sizeof(struct sockaddr)); 93 | } else { 94 | he_session_reject(state, addr); 95 | goto cleanup; 96 | } 97 | } 98 | } else { 99 | LW_CHECK_WITH_MSG(state->he_conn, "Client should not exist without initialised he_conn"); 100 | } 101 | 102 | he_return_code_t res = he_conn_outside_data_received(state->he_conn, (uint8_t *)buf->base, nread); 103 | 104 | if(res != HE_SUCCESS) { 105 | bool fatal = he_conn_is_error_fatal(state->he_conn, res); 106 | zlogf_time(ZLOG_INFO_LOG_MSG, "Non-zero return code from libhelium: %s Fatal?: %s", he_return_code_name(res), 107 | fatal ? "true" : "false"); 108 | if(fatal) { 109 | lw_state_disconnect(state); 110 | } 111 | goto cleanup; 112 | } 113 | 114 | cleanup: 115 | if(buf) { 116 | free(buf->base); 117 | } 118 | 119 | return; 120 | } 121 | 122 | void on_send(uv_udp_send_t *req, int status) { 123 | send_req_t *send_req = (send_req_t *)req; 124 | free(send_req->buf.base); 125 | free(send_req); 126 | } 127 | 128 | he_return_code_t udp_write_cb(he_conn_t *he_conn, uint8_t *packet, size_t length, void *context) { 129 | // Get our context back 130 | lw_state_t *state = (lw_state_t *)context; 131 | 132 | send_req_t *req = (send_req_t *)calloc(1, sizeof(send_req_t)); 133 | LW_CHECK_WITH_MSG(req, "Unable to allocate write request!"); 134 | 135 | uint8_t *output_buffer = calloc(1, LW_MAX_WIRE_MTU); 136 | LW_CHECK_WITH_MSG(output_buffer, "Unable to allocate write buffer"); 137 | memcpy(output_buffer, packet, length); 138 | 139 | req->buf = uv_buf_init((char *)output_buffer, (unsigned int)length); 140 | 141 | int res = uv_udp_send((uv_udp_send_t *)req, &state->udp_socket, &req->buf, 1, 142 | (const struct sockaddr *)&state->send_addr, on_send); 143 | 144 | if(res) { 145 | zlogf_time(ZLOG_INFO_LOG_MSG, "Error occurred during uv_write: %s (%d)\n", uv_strerror(res), 146 | res); 147 | return HE_ERR_CALLBACK_FAILED; 148 | } 149 | 150 | return HE_SUCCESS; 151 | } 152 | 153 | void he_session_reject(lw_state_t *state, const struct sockaddr *addr) { 154 | // TODO Normalise this with above 155 | 156 | // Session Error identifier 157 | uint64_t error = HE_PACKET_SESSION_REJECT; 158 | 159 | // Allocate send request 160 | send_req_t *req = (send_req_t *)calloc(1, sizeof(send_req_t)); 161 | LW_CHECK_WITH_MSG(req, "Unable to allocate request"); 162 | 163 | // Allocate buffer 164 | char *write_buf = (char *)calloc(1, sizeof(he_wire_hdr_t)); 165 | LW_CHECK_WITH_MSG(write_buf, "Unable to allocate write_buf"); 166 | 167 | he_wire_hdr_t *hdr = (he_wire_hdr_t *)write_buf; 168 | 169 | hdr->he[0] = 'H'; 170 | hdr->he[1] = 'e'; 171 | 172 | hdr->major_version = 1; 173 | hdr->minor_version = 0; 174 | 175 | // Memcpy in the session identifier 176 | memcpy(&hdr->session, &error, sizeof(uint64_t)); 177 | 178 | // Initialise the write buffer 179 | req->buf = uv_buf_init(write_buf, sizeof(he_wire_hdr_t)); 180 | 181 | // Write it out 182 | int err = uv_udp_send((uv_udp_send_t *)req, &state->udp_socket, &req->buf, 1, addr, on_send); 183 | 184 | if(err) { 185 | zlogf_time(ZLOG_INFO_LOG_MSG, "Error occurred during session reject on uv_udp_send: %d\n", err); 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/udp/flow.h: -------------------------------------------------------------------------------- 1 | /* * 2 | * Lightway Laser 3 | * Copyright (C) 2021 Express VPN International Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef LW_FLOW_H 21 | #define LW_FLOW_H 22 | 23 | #include 24 | 25 | void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf); 26 | void on_read(uv_udp_t *handle, ssize_t nread, const uv_buf_t *buf, const struct sockaddr *addr, 27 | unsigned flags); 28 | 29 | void he_session_reject(lw_state_t *state, const struct sockaddr *addr); 30 | 31 | he_return_code_t udp_write_cb(he_conn_t *he_conn, uint8_t *packet, size_t length, void *context); 32 | 33 | #endif // LW_FLOW_H 34 | -------------------------------------------------------------------------------- /src/udp/server.c: -------------------------------------------------------------------------------- 1 | /* * 2 | * Lightway Laser 3 | * Copyright (C) 2021 Express VPN International Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include "server.h" 21 | #include "flow.h" 22 | #include "util.h" 23 | 24 | void configure_udp_server(lw_config_t *config, lw_state_t *state) { 25 | zlogf_time(ZLOG_INFO_LOG_MSG, "Configuring UDP Server...\n"); 26 | 27 | int res = uv_udp_init(state->loop, &state->udp_socket); 28 | LW_CHECK_WITH_MSG(res == 0, "Unable to initialise UDP socket"); 29 | 30 | struct sockaddr_in recv_addr; 31 | res = uv_ip4_addr(config->server_ip, config->server_port, &recv_addr); 32 | LW_CHECK_WITH_MSG(res == 0, "Invalid IP address or port"); 33 | 34 | res = uv_udp_bind(&state->udp_socket, (const struct sockaddr *)&recv_addr, UV_UDP_REUSEADDR); 35 | LW_CHECK_WITH_MSG(res == 0, "Unable to bind UDP socket"); 36 | 37 | int udp_buffer_size = 15 * MEGABYTE; 38 | uv_send_buffer_size((uv_handle_t *)&state->udp_socket, &udp_buffer_size); 39 | uv_recv_buffer_size((uv_handle_t *)&state->udp_socket, &udp_buffer_size); 40 | 41 | state->udp_socket.data = state; 42 | he_ssl_ctx_set_outside_write_cb(state->he_ctx, udp_write_cb); 43 | 44 | return; 45 | } 46 | 47 | void start_udp_server(lw_state_t *state) { 48 | int res = uv_udp_recv_start(&state->udp_socket, alloc_buffer, on_read); 49 | LW_CHECK_WITH_MSG(res == 0, "Unable to start recv on udp socket"); 50 | 51 | return; 52 | } 53 | -------------------------------------------------------------------------------- /src/udp/server.h: -------------------------------------------------------------------------------- 1 | /* * 2 | * Lightway Laser 3 | * Copyright (C) 2021 Express VPN International Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef LW_UDP_SERVER_H 21 | #define LW_UDP_SERVER_H 22 | 23 | #include 24 | 25 | void configure_udp_server(lw_config_t *config, lw_state_t *state); 26 | 27 | void start_udp_server(lw_state_t *state); 28 | 29 | #endif // LW_UDP_SERVER_H 30 | -------------------------------------------------------------------------------- /src/util.c: -------------------------------------------------------------------------------- 1 | /* * 2 | * Lightway Laser 3 | * Copyright (C) 2021 Express VPN International Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | /* Convert IP string to 32 bit unsigned int */ 31 | uint32_t ip2int(const char *ip) { 32 | struct in_addr a; 33 | if(!inet_aton(ip, &a)) { 34 | // IP was invalid - return 0 35 | return ((uint32_t)0); 36 | } 37 | return a.s_addr; 38 | } 39 | 40 | size_t slurp_file(char *path, char **buf) { 41 | int fd = open(path, O_RDONLY); 42 | LW_CHECK_WITH_MSG(fd > 0, "Unable to open file"); 43 | 44 | int len = lseek(fd, 0, SEEK_END); 45 | LW_CHECK_WITH_MSG(len > 0, "Unable to calculate file length"); 46 | 47 | void *data = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0); 48 | LW_CHECK_WITH_MSG(data, "Unable to mmap file"); 49 | 50 | *buf = data; 51 | 52 | return len; 53 | } 54 | 55 | void unslurp_file(char *buf, size_t length) { 56 | munmap(buf, length); 57 | } 58 | -------------------------------------------------------------------------------- /src/util.h: -------------------------------------------------------------------------------- 1 | /* * 2 | * Lightway Laser 3 | * Copyright (C) 2021 Express VPN International Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | /* Convert IP string to 32 bit unsigned int */ 24 | uint32_t ip2int(const char *ip); 25 | 26 | /* Slurp a file into a buffer */ 27 | size_t slurp_file(char *path, char **buf); 28 | void unslurp_file(char *buf, size_t length); 29 | 30 | /** 31 | * Size of 1MB in bytes for clearer code 32 | */ 33 | #define MEGABYTE (1024 * 1024) 34 | 35 | /** 36 | * Macro to exit the program with error performing any necessary tear down 37 | */ 38 | #define LW_EXIT_WITH_FAILURE() exit(EXIT_FAILURE) 39 | 40 | /** 41 | * Exit the program if this expression isn't true (should be used where condition violation is a 42 | * serious / impossible error) Similar to assert but runs outside of debug mode 43 | */ 44 | #ifdef TEST 45 | #define LW_CHECK_WITH_MSG(expression, msg) \ 46 | if(!(expression)) { \ 47 | TEST_FAIL_MESSAGE("Fatal assertion " #expression " caused check failure"); \ 48 | } 49 | #else 50 | #define LW_CHECK_WITH_MSG(expression, msg) \ 51 | if(!(expression)) { \ 52 | zlogf_time(ZLOG_INFO_LOG_MSG, \ 53 | "Fatal assertion " #expression " violated (%s) in %s at %s:%i\n", (msg), __FILE__, \ 54 | __func__, __LINE__); \ 55 | zlog_finish(); \ 56 | LW_EXIT_WITH_FAILURE(); \ 57 | } 58 | #endif 59 | -------------------------------------------------------------------------------- /test/support/libhe_testable_types.h: -------------------------------------------------------------------------------- 1 | /* * 2 | * Lightway Laser 3 | * Copyright (C) 2021 Express VPN International Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef LIBHE_TESTABLE_TYPES 21 | #define LIBHE_TESTABLE_TYPES 22 | 23 | typedef struct he_client { 24 | int id; 25 | } he_client_t; 26 | 27 | typedef struct he_ssl_ctx_config { 28 | int id; 29 | } he_ssl_ctx_config_t; 30 | 31 | typedef struct he_ssl_ctx { 32 | int id; 33 | } he_ssl_ctx_t; 34 | 35 | typedef struct he_conn_config { 36 | int id; 37 | } he_conn_config_t; 38 | 39 | typedef struct he_conn { 40 | int id; 41 | } he_conn_t; 42 | 43 | typedef struct he_plugin_chain { 44 | int id; 45 | } he_plugin_chain_t; 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /test/support/test_defs.h: -------------------------------------------------------------------------------- 1 | /* * 2 | * Lightway Laser 3 | * Copyright (C) 2021 Express VPN International Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef LW_TEST_DEFS_H 21 | #define LW_TEST_DEFS_H 22 | 23 | char *max_string = "aaaaaaa"; 24 | 25 | #endif // LW_TEST_DEFS_H 26 | -------------------------------------------------------------------------------- /test/test_util.c: -------------------------------------------------------------------------------- 1 | /* * 2 | * Lightway Laser 3 | * Copyright (C) 2021 Express VPN International Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include 21 | #include "unity.h" 22 | #include "test_defs.h" 23 | 24 | // Unit under test 25 | #include "util.h" 26 | 27 | void setUp(void) { 28 | } 29 | 30 | void tearDown(void) { 31 | } 32 | 33 | void test_max_string(void) { 34 | TEST_ASSERT_EQUAL_STRING("aaaaaaa", max_string); 35 | } 36 | --------------------------------------------------------------------------------