├── README.md ├── LICENSE └── lnxrouter /README.md: -------------------------------------------------------------------------------- 1 | # Linux-router 2 | 3 | Set Linux as router in one command. Able to provide Internet, or create WiFi hotspot. Support transparent proxy (redsocks). Also useful for routing VM/containers. 4 | 5 | It wraps `iptables`, `dnsmasq` etc. stuff. Use in one command, restore in one command or by `control-c` (or even by closing terminal window). 6 | 7 | [More tools and projects 🛠️](https://garywill.github.io) | [🍻 Buy me a coffee ❤️](https://github.com/garywill/receiving/blob/master/receiving_methods.md) 8 | 9 | 10 | ## Features 11 | 12 | Basic features: 13 | 14 | - Create a NATed sub-network 15 | - Provide Internet 16 | - DHCP server (and RA) 17 | - Specify what DNS the DHCP server assigns to clients 18 | - DNS server 19 | - Specify upstream DNS (kind of a plain DNS proxy) 20 | - IPv6 (behind NATed LAN, like IPv4) 21 | - Creating WiFi hotspot: 22 | - Wifi 3/4/5/6 23 | - 2.4GHz, 5GHz 24 | - Channel selecting 25 | - Choose encryptions: WPA2/WPA, WPA2, WPA, No encryption 26 | - Create AP on the same interface you are getting Internet (Need hardware support. Usually require same channel) 27 | - Transparent proxy (redsocks) 28 | - Transparent DNS proxy (hijack port 53 packets) 29 | - Detect and prevent interference from following Linux system daemons: 30 | - NetworkManager (handle interface (un)managed status) 31 | - firewalld (use temporary `trusted` zone) 32 | - Instances managing. You can run multiple instances, to create different sub-networks. 33 | 34 | **For many other features, see below [CLI usage](#cli-usage-and-other-features)** 35 | 36 | ### Useful in these situations 37 | 38 | ``` 39 | Internet----(eth0/wlan0)-Linux-(wlanX)AP 40 | |--client 41 | |--client 42 | ``` 43 | 44 | ``` 45 | Internet 46 | WiFi AP(no DHCP) | 47 | |----(wlan1)-Linux-(eth0/wlan0)------ 48 | | (DHCP) 49 | |--client 50 | |--client 51 | ``` 52 | 53 | ``` 54 | Internet 55 | Switch | 56 | |---(eth1)-Linux-(eth0/wlan0)-------- 57 | |--client 58 | |--client 59 | ``` 60 | 61 | ``` 62 | Internet----(eth0/wlan0)-Linux-(eth1)------Another PC 63 | ``` 64 | 65 | ``` 66 | Internet----(eth0/wlan0)-Linux-(virtual interface)-----VM/container 67 | ``` 68 | 69 | ## Install 70 | 71 | 1-file-script. Release on [Linux-router repo on Github](https://github.com/garywill/linux-router). Just download and run the bash script (meet the dependencies). In this case use without installation. 72 | 73 | I'm currently not packaging for any distro. If you do, open a PR and add the link (can be with a version badge) to list here 74 | 75 | | Linux distro | | 76 | | ------------ | ---------------------------------------------------------------------------------------------------------- | 77 | | Any | download [1-file-script](https://raw.githubusercontent.com/garywill/linux-router/master/lnxrouter) and run without installation | 78 | 79 | ### Dependencies 80 | 81 | - bash 82 | - procps or procps-ng 83 | - iproute2 84 | - dnsmasq 85 | - iptables (or nftables with `iptables-nft` translation linked) 86 | - WiFi hotspot dependencies 87 | - hostapd 88 | - iw (or iwconfig, when iw can not recognize adapter) 89 | - haveged (optional) 90 | - crda and wireless-regdb (optional) 91 | 92 | 93 | 94 | ## Usage 95 | 96 | ### Provide Internet to an interface 97 | 98 | ```bash 99 | sudo lnxrouter -i eth1 100 | ``` 101 | 102 | no matter which interface (other than `eth1`) you're getting Internet from. 103 | 104 | ### Create WiFi hotspot 105 | 106 | ```bash 107 | sudo lnxrouter --ap wlan0 MyAccessPoint -p MyPassPhrase 108 | ``` 109 | 110 | no matter which interface you're getting Internet from (even from `wlan0`). Will create virtual Interface `x0wlan0` for hotspot. 111 | 112 | ### Provide an interface's Internet to another interface 113 | 114 | Clients access Internet through only `isp5` 115 | 116 |
117 | 118 | ```bash 119 | sudo lnxrouter -i eth1 -o isp5 --no-dns --dhcp-dns 1.1.1.1 -6 --dhcp-dns6 [2606:4700:4700::1111] 120 | ``` 121 | 122 | > In this case of usage, it's recommended to: 123 | > 124 | > 1. Stop serving local DNS 125 | > 2. Tell clients which DNS to use (ISP5's DNS. Or, a safe public DNS, like above example) 126 | 127 |
128 | 129 | ### Create LAN without providing Internet 130 | 131 |
132 | 133 | ```bash 134 | sudo lnxrouter -n -i eth1 135 | ``` 136 | 137 | ```bash 138 | sudo lnxrouter -n --ap wlan0 MyAccessPoint -p MyPassPhrase 139 | ``` 140 | 141 |
142 | 143 | ### Internet for LXC 144 | 145 |
146 | 147 | Create a bridge 148 | 149 | ```bash 150 | sudo brctl addbr lxcbr5 151 | ``` 152 | 153 | In LXC container `config` 154 | 155 | ``` 156 | lxc.network.type = veth 157 | lxc.network.flags = up 158 | lxc.network.link = lxcbr5 159 | lxc.network.hwaddr = xx:xx:xx:xx:xx:xx 160 | ``` 161 | 162 | ```bash 163 | sudo lnxrouter -i lxcbr5 164 | ``` 165 | 166 |
167 | 168 | ### Transparent proxy 169 | 170 | All clients' Internet traffic go through, for example, Tor (notice this example is NOT an anonymity use) 171 | 172 |
173 | 174 | ```bash 175 | sudo lnxrouter -i eth1 --tp 9040 --dns 9053 -g 192.168.55.1 -6 --p6 fd00:5:6:7:: 176 | ``` 177 | 178 | In `torrc` 179 | 180 | ``` 181 | TransPort 192.168.55.1:9040 182 | DNSPort 192.168.55.1:9053 183 | TransPort [fd00:5:6:7::1]:9040 184 | DNSPort [fd00:5:6:7::1]:9053 185 | ``` 186 | 187 | > **Warn**: Tor's anonymity relies on a purpose-made browser. Using Tor like this (sharing Tor's network to LAN clients) will NOT ensure anonymity. 188 | > 189 | > Although we use Tor as example here, Linux-router does NOT ensure nor is NOT aiming at anonymity. 190 | 191 |
192 | 193 | ### Clients-in-sandbox network 194 | 195 | To not give our infomation to clients. Clients can still access Internet. 196 | 197 |
198 | 199 | ```bash 200 | sudo lnxrouter -i eth1 \ 201 | --tp 9040 --dns 9053 \ 202 | --random-mac \ 203 | --ban-priv \ 204 | --catch-dns --log-dns # optional 205 | ``` 206 | 207 |
208 | 209 | > Linux-router comes with no warranty. Use on your own risk 210 | 211 | ### Use as transparent proxy for LXD 212 | 213 |
214 | 215 | Create a bridge 216 | 217 | ```bash 218 | sudo brctl addbr lxdbr5 219 | ``` 220 | 221 | Create and add a new LXD profile overriding container's `eth0` 222 | 223 | ```bash 224 | lxc profile create profile5 225 | lxc profile edit profile5 226 | 227 | ### profile content ### 228 | config: {} 229 | description: "" 230 | devices: 231 | eth0: 232 | name: eth0 233 | nictype: bridged 234 | parent: lxdbr5 235 | type: nic 236 | name: profile5 237 | 238 | lxc profile add profile5 239 | ``` 240 | 241 | ```bash 242 | sudo lnxrouter -i lxdbr5 --tp 9040 --dns 9053 243 | ``` 244 | 245 | To remove that new profile from container 246 | 247 | ```bash 248 | lxc profile remove profile5 249 | ``` 250 | 251 | #### To not use profile 252 | 253 | Add new `eth0` to container overriding default `eth0` 254 | 255 | ```bash 256 | lxc config device add eth0 nic name=eth0 nictype=bridged parent=lxdbr5 257 | ``` 258 | 259 | To remove the customized `eth0` to restore default `eth0` 260 | 261 | ```bash 262 | lxc config device remove eth0 263 | ``` 264 | 265 |
266 | 267 | ### Use as transparent proxy for VirtualBox 268 | 269 |
270 | 271 | In VirtualBox's global settings, create a host-only network `vboxnet5` with DHCP disabled. 272 | 273 | ```bash 274 | sudo lnxrouter -i vboxnet5 --tp 9040 --dns 9053 275 | ``` 276 | 277 |
278 | 279 | ### Use as transparent proxy for firejail 280 | 281 |
282 | 283 | Create a bridge 284 | 285 | ```bash 286 | sudo brctl addbr firejail5 287 | ``` 288 | 289 | ```bash 290 | sudo lnxrouter -i firejail5 -g 192.168.55.1 --tp 9040 --dns 9053 291 | firejail --net=firejail5 --dns=192.168.55.1 --blacklist=/var/run/nscd 292 | ``` 293 | 294 | Firejail's `/etc/resolv.conf` doesn't obtain DNS from DHCP, so we need to assign. 295 | 296 | nscd is domain name cache service, which shouldn't be accessed from in jail here. 297 | 298 |
299 | 300 | ### CLI usage and other features 301 | 302 |
303 | 304 | ``` 305 | Usage: lnxrouter 306 | 307 | Options: 308 | -h, --help Show this help 309 | --version Print version number 310 | 311 | -i Interface to make NATed sub-network, 312 | and to provide Internet to 313 | (To create WiFi hotspot use '--ap' instead) 314 | -o Specify an inteface to provide Internet from. 315 | (Note using this with default DNS option may leak 316 | queries to other interfaces) 317 | -n Do not provide Internet 318 | --ban-priv Disallow clients to access my private network 319 | 320 | -g This host's IPv4 address in subnet (mask is /24) 321 | (example: '192.168.5.1' or '5' shortly) 322 | -6 Enable IPv6 (NAT) 323 | --no4 Disable IPv4 Internet (not forwarding IPv4). 324 | Usually used with '-6' 325 | 326 | --p6 Set IPv6 LAN address prefix (length 64) 327 | (example: 'fd00:0:0:5::' or '5' shortly) 328 | Using this enables '-6' 329 | 330 | --dns || 331 | DNS server's upstream DNS. 332 | Use ',' to seperate multiple servers 333 | (default: use /etc/resolv.conf) 334 | (Note IPv6 addresses need '[]' around) 335 | --no-dns Do not serve DNS 336 | --no-dnsmasq Disable dnsmasq server (DHCP, DNS, RA) 337 | --catch-dns Transparent DNS proxy, redirect packets(TCP/UDP) 338 | whose destination port is 53 to this host 339 | --log-dns Show DNS query log (dnsmasq) 340 | --dhcp-dns |no 341 | Set IPv4 DNS offered by DHCP (default: this host). 342 | --dhcp-dns6 |no 343 | Set IPv6 DNS offered by DHCP (RA) 344 | (default: this host) 345 | (Note IPv6 addresses need '[]' around) 346 | Using both above two will enable '--no-dns' 347 | --hostname DNS server associate this name with this host. 348 | Use '-' to read name from /etc/hostname 349 | -d DNS server will take into account /etc/hosts 350 | -e DNS server will take into account additional 351 | hosts file 352 | --dns-nocache DNS server no cache 353 | 354 | --mac Set MAC address 355 | --random-mac Use random MAC address 356 | 357 | --tp Transparent proxy, 358 | redirect non-LAN TCP and UDP(not tested) traffic to 359 | port. (usually used with '--dns') 360 | 361 | WiFi hotspot options: 362 | --ap 363 | Create WiFi access point 364 | -p, --password 365 | WiFi password 366 | --qr Show WiFi QR code in terminal (need qrencode) 367 | 368 | --hidden Hide access point (not broadcast SSID) 369 | --no-virt Do not create virtual interface 370 | Using this you can't use same wlan interface 371 | for both Internet and AP 372 | --virt-name Set name of virtual interface 373 | -c Specify channel (default: use current, or 1 / 36) 374 | --country Set two-letter country code for regularity 375 | (example: US) 376 | --freq-band Set frequency band: 2.4 or 5 (default: 2.4) 377 | --driver Choose your WiFi adapter driver (default: nl80211) 378 | -w '2' for WPA2, '1' for WPA, '1+2' for both 379 | (default: 2) 380 | --psk Use 64 hex digits pre-shared-key instead of 381 | passphrase 382 | --mac-filter Enable WiFi hotspot MAC address filtering 383 | --mac-filter-accept Location of WiFi hotspot MAC address filter list 384 | (defaults to /etc/hostapd/hostapd.accept) 385 | --hostapd-debug 1 or 2. Passes -d or -dd to hostapd 386 | --isolate-clients Disable wifi communication between clients 387 | --sta-timeout Timeout to disconnect a no-signal client 388 | --no-haveged Do not run haveged automatically when needed 389 | --hs20 Enable Hotspot 2.0 390 | 391 | WiFi 4 (802.11n) configs (2.4G/5GHz): (default: not enable) 392 | --wifi4 Enable IEEE 802.11n (HT, High Throughput) 393 | --ht-capab HT capabilities (example: '[HT40+][DSSS_CCK-40]') 394 | (default: '[HT40+]') 395 | --req-wifi4 Only support Wifi>=4 clients 396 | 397 | WiFi 5 (802.11ac) configs (5GHz): (default: not enable) 398 | --wifi5 Enable IEEE 802.11ac (VHT, Very High Thoughtput) 399 | --vht-capab VHT capabilities (example: '[VHT160][RXLDPC]') 400 | --vht-ch-width Index of VHT channel width: 401 | 0 for 20MHz or 40MHz (default) 402 | 1 for 80MHz 403 | 2 for 160MHz 404 | 3 for 80+80MHz (Non-contigous 160MHz) 405 | --vht-seg0-ch Channel index of VHT center frequency for primary 406 | segment. Use with '--vht-ch-width' 407 | --vht-seg1-ch Channel index of VHT center frequency for secondary 408 | (second 80MHz) segment. Use with '--vht-ch-width 3' 409 | --req-wifi5 Only support Wifi>=5 clients 410 | 411 | WiFi 6 (802.11ax) configs (2.4G/5GHz): (default: not enable) 412 | --wifi6 Enable IEEE 802.11ax (HE, High Efficiency) 413 | --he-ch-width Index of HE channel width: 414 | 0 for 20MHz or 40MHz (default) 415 | 1 for 80MHz 416 | 2 for 160MHz 417 | 3 for 80+80MHz (Non-contigous 160MHz) 418 | --he-seg0-ch Channel index of HE center frequency for primary 419 | segment. Use with '--he-ch-width' 420 | --he-seg1-ch Channel index of HE center frequency for secondary 421 | (second 80MHz) segment. Use with '--he-ch-width 3' 422 | --he-su-bfe HE Single User Beamformee support 423 | --he-su-bfr HE Single User Beamformer support 424 | --he-mu-bfr HE Multi User Beamformer support 425 | --req-wifi6 Only support Wifi>=6 clients 426 | --p2ptwt Peer-to-Peer Target Wake Time support 427 | 428 | Note: Some cutting-edge Wifi features strongly depends on hostapd built 429 | with specific flags enabled and compatible hardware 430 | 431 | Instance managing: 432 | --daemon Run in background 433 | --keep-confdir Don't delete the temporary config dir after exit 434 | 435 | -l, --list-running Show running instances 436 | --lc, --list-clients 437 | List clients of an instance. Or list neighbors of 438 | an interface, even if it isn't handled by us. 439 | (passive mode) 440 | --stop Stop a running instance 441 | For you can use PID or subnet interface name. 442 | You can get them with '--list-running' 443 | ``` 444 | 445 |
446 | 447 | ## System admins should know 448 | 449 | ### Take care of concurrency 450 | 451 | Linux-router script is home-made, not enterprise-level. 452 | 453 | - You can run multiple linux-router instances and they work simultaneous, as long as you start/stop **one by one**, not all at once. We **can't ensure** its locks covering 100% race condition edge cases. 454 | 455 | - Use it after the system has fully booted. When you’re manually (re)starting/stopping some network-related services, stop linux-router first, otherwise those services (flushing iptables or some) may break linux-router's setup. 456 | 457 | ### What changes are done to Linux system 458 | 459 | On exit of a linux-router instance, script **will do cleanup**, i.e. undo most changes to system. Though, **some** changes (if needed) will **not** be undone, which are: 460 | 461 | 1. `/proc/sys/net/ipv4/ip_forward = 1` and `/proc/sys/net/ipv6/conf/all/forwarding = 1` 462 | 2. dnsmasq in Apparmor complain mode 463 | 3. hostapd in Apparmor complain mode 464 | 4. Kernel module `nf_nat_pptp` loaded 465 | 5. The wifi device which is used to create hotspot is `rfkill unblock`ed 466 | 6. WiFi country code, if user assigns 467 | 468 | ## Meet contributor(s) and become one of them 469 | 470 | Visit [**my homepage** 🏡](https://garywill.github.io) to see **more tools and projects** 🛠️. 471 | 472 | > [❤️ Buy me a coffee](https://github.com/garywill/receiving/blob/master/receiving_methods.md) , this project took me lots of time! ([❤️ 扫码领红包并打赏一个!](https://github.com/garywill/receiving/blob/master/receiving_methods.md)) 473 | > 474 | > 🥂 ( ^\_^) o自自o (^_^ ) 🍻 475 | 476 | 🤝 Bisides, thank [create_ap](https://github.com/oblique/create_ap) by [oblique](https://github.com/oblique). This script was forked from create\_ap. Now they are quite different. 🤝 Also thank those people who contributed to that project. 477 | 478 | 👨‍💻 You can be contributor, too! 479 | 480 | - 🍃 There're some TO-DOs listed, in both [readme TODO](#todo) and [in the code file](https://github.com/garywill/linux-router/search?q=TODO&type=code) 481 | - 🍃 Also some [unfulfilled enhancements in the Issues](https://github.com/garywill/linux-router/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement) 482 | - 🙋‍♂️ Contributions are not limited to coding. There're [some posts and questions](https://github.com/garywill/linux-router/issues) that need more people to answer 483 | 484 | ## TODO 485 | - WPA3 486 | - Global IPv6 487 | 488 | ## License 489 | 490 | linux-router is LGPL licensed 491 | 492 |
493 | 494 | ``` 495 | linux-router 496 | Copyright (C) 2018 garywill 497 | 498 | This library is free software; you can redistribute it and/or 499 | modify it under the terms of the GNU Lesser General Public 500 | License as published by the Free Software Foundation; either 501 | version 2.1 of the License, or (at your option) any later version. 502 | 503 | This library is distributed in the hope that it will be useful, 504 | but WITHOUT ANY WARRANTY; without even the implied warranty of 505 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 506 | Lesser General Public License for more details. 507 | 508 | You should have received a copy of the GNU Lesser General Public 509 | License along with this library; if not, write to the Free Software 510 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 511 | ``` 512 | 513 |
514 | 515 | Upstream create_ap was BSD licensed 516 | 517 |
518 | 519 | ``` 520 | Copyright (c) 2013, oblique 521 | All rights reserved. 522 | 523 | Redistribution and use in source and binary forms, with or without 524 | modification, are permitted provided that the following conditions are met: 525 | 526 | * Redistributions of source code must retain the above copyright notice, this 527 | list of conditions and the following disclaimer. 528 | 529 | * Redistributions in binary form must reproduce the above copyright notice, 530 | this list of conditions and the following disclaimer in the documentation 531 | and/or other materials provided with the distribution. 532 | 533 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 534 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 535 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 536 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 537 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 538 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 539 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 540 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 541 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 542 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 543 | ``` 544 | 545 |
546 | 547 | 548 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 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 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 489 | 490 | Also add information on how to contact you by electronic and paper mail. 491 | 492 | You should also get your employer (if you work as a programmer) or your 493 | school, if any, to sign a "copyright disclaimer" for the library, if 494 | necessary. Here is a sample; alter the names: 495 | 496 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 497 | library `Frob' (a library for tweaking knobs) written by James Random Hacker. 498 | 499 | , 1 April 1990 500 | Ty Coon, President of Vice 501 | 502 | That's all there is to it! 503 | -------------------------------------------------------------------------------- /lnxrouter: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | VERSION=0.8.1 4 | PROGNAME="$(basename "$0")" 5 | 6 | export LC_ALL=C 7 | 8 | SCRIPT_UMASK=0122 9 | umask $SCRIPT_UMASK 10 | 11 | phead() { 12 | echo "linux-router $VERSION (https://github.com/garywill/linux-router)" 13 | } 14 | phead2() { 15 | echo "Released under LGPL, with no warranty. Use on your own risk." 16 | } 17 | usage() { 18 | phead 19 | phead2 20 | cat << EOF 21 | 22 | Usage: $PROGNAME 23 | 24 | Options: 25 | -h, --help Show this help 26 | --version Print version number 27 | 28 | -i Interface to make NATed sub-network, 29 | and to provide Internet to 30 | (To create WiFi hotspot use '--ap' instead) 31 | -o Specify an inteface to provide Internet from. 32 | (Note using this with default DNS option may leak 33 | queries to other interfaces) 34 | -n Do not provide Internet 35 | --ban-priv Disallow clients to access my private network 36 | 37 | -g This host's IPv4 address in subnet (mask is /24) 38 | (example: '192.168.5.1' or '5' shortly) 39 | -6 Enable IPv6 (NAT) 40 | --no4 Disable IPv4 Internet (not forwarding IPv4). 41 | Usually used with '-6' 42 | 43 | --p6 Set IPv6 LAN address prefix (length 64) 44 | (example: 'fd00:0:0:5::' or '5' shortly) 45 | Using this enables '-6' 46 | 47 | --dns || 48 | DNS server's upstream DNS. 49 | Use ',' to seperate multiple servers 50 | (default: use /etc/resolv.conf) 51 | (Note IPv6 addresses need '[]' around) 52 | --no-dns Do not serve DNS 53 | --no-dnsmasq Disable dnsmasq server (DHCP, DNS, RA) 54 | --catch-dns Transparent DNS proxy, redirect packets(TCP/UDP) 55 | whose destination port is 53 to this host 56 | --log-dns Show DNS query log (dnsmasq) 57 | --dhcp-dns |no 58 | Set IPv4 DNS offered by DHCP (default: this host). 59 | --dhcp-dns6 |no 60 | Set IPv6 DNS offered by DHCP (RA) 61 | (default: this host) 62 | (Note IPv6 addresses need '[]' around) 63 | Using both above two will enable '--no-dns' 64 | --hostname DNS server associate this name with this host. 65 | Use '-' to read name from /etc/hostname 66 | -d DNS server will take into account /etc/hosts 67 | -e DNS server will take into account additional 68 | hosts file 69 | --dns-nocache DNS server no cache 70 | 71 | --mac Set MAC address 72 | --random-mac Use random MAC address 73 | 74 | --tp Transparent proxy, 75 | redirect non-LAN TCP and UDP(not tested) traffic to 76 | port. (usually used with '--dns') 77 | 78 | WiFi hotspot options: 79 | --ap 80 | Create WiFi access point 81 | -p, --password 82 | WiFi password 83 | --qr Show WiFi QR code in terminal (need qrencode) 84 | 85 | --hidden Hide access point (not broadcast SSID) 86 | --no-virt Do not create virtual interface 87 | Using this you can't use same wlan interface 88 | for both Internet and AP 89 | --virt-name Set name of virtual interface 90 | -c Specify channel (default: use current, or 1 / 36) 91 | --country Set two-letter country code for regularity 92 | (example: US) 93 | --freq-band Set frequency band: 2.4 or 5 (default: 2.4) 94 | --driver Choose your WiFi adapter driver (default: nl80211) 95 | -w '2' for WPA2, '1' for WPA, '1+2' for both 96 | (default: 2) 97 | --psk Use 64 hex digits pre-shared-key instead of 98 | passphrase 99 | --mac-filter Enable WiFi hotspot MAC address filtering 100 | --mac-filter-accept Location of WiFi hotspot MAC address filter list 101 | (defaults to /etc/hostapd/hostapd.accept) 102 | --hostapd-debug 1 or 2. Passes -d or -dd to hostapd 103 | --isolate-clients Disable wifi communication between clients 104 | --sta-timeout Timeout to disconnect a no-signal client 105 | --no-haveged Do not run haveged automatically when needed 106 | --hs20 Enable Hotspot 2.0 107 | 108 | WiFi 4 (802.11n) configs (2.4G/5GHz): (default: not enable) 109 | --wifi4 Enable IEEE 802.11n (HT, High Throughput) 110 | --ht-capab HT capabilities (example: '[HT40+][DSSS_CCK-40]') 111 | (default: '[HT40+]') 112 | --req-wifi4 Only support Wifi>=4 clients 113 | 114 | WiFi 5 (802.11ac) configs (5GHz): (default: not enable) 115 | --wifi5 Enable IEEE 802.11ac (VHT, Very High Thoughtput) 116 | --vht-capab VHT capabilities (example: '[VHT160][RXLDPC]') 117 | --vht-ch-width Index of VHT channel width: 118 | 0 for 20MHz or 40MHz (default) 119 | 1 for 80MHz 120 | 2 for 160MHz 121 | 3 for 80+80MHz (Non-contigous 160MHz) 122 | --vht-seg0-ch Channel index of VHT center frequency for primary 123 | segment. Use with '--vht-ch-width' 124 | --vht-seg1-ch Channel index of VHT center frequency for secondary 125 | (second 80MHz) segment. Use with '--vht-ch-width 3' 126 | --req-wifi5 Only support Wifi>=5 clients 127 | 128 | WiFi 6 (802.11ax) configs (2.4G/5GHz): (default: not enable) 129 | --wifi6 Enable IEEE 802.11ax (HE, High Efficiency) 130 | --he-ch-width Index of HE channel width: 131 | 0 for 20MHz or 40MHz (default) 132 | 1 for 80MHz 133 | 2 for 160MHz 134 | 3 for 80+80MHz (Non-contigous 160MHz) 135 | --he-seg0-ch Channel index of HE center frequency for primary 136 | segment. Use with '--he-ch-width' 137 | --he-seg1-ch Channel index of HE center frequency for secondary 138 | (second 80MHz) segment. Use with '--he-ch-width 3' 139 | --he-su-bfe HE Single User Beamformee support 140 | --he-su-bfr HE Single User Beamformer support 141 | --he-mu-bfr HE Multi User Beamformer support 142 | --req-wifi6 Only support Wifi>=6 clients 143 | --p2ptwt Peer-to-Peer Target Wake Time support 144 | 145 | Note: Some cutting-edge Wifi features strongly depends on hostapd built 146 | with specific flags enabled and compatible hardware 147 | 148 | Instance managing: 149 | --daemon Run in background 150 | --keep-confdir Don't delete the temporary config dir after exit 151 | 152 | -l, --list-running Show running instances 153 | --lc, --list-clients 154 | List clients of an instance. Or list neighbors of 155 | an interface, even if it isn't handled by us. 156 | (passive mode) 157 | --stop Stop a running instance 158 | For you can use PID or subnet interface name. 159 | You can get them with '--list-running' 160 | 161 | Examples: 162 | $PROGNAME -i eth1 163 | $PROGNAME --ap wlan0 MyAccessPoint -p MyPassPhrase 164 | $PROGNAME -i eth1 --tp --dns 165 | EOF 166 | } 167 | 168 | check_empty_option(){ 169 | if [[ "$1" == "" ]]; then 170 | usage 171 | exit 0 172 | fi 173 | } 174 | 175 | 176 | define_global_variables(){ 177 | # user options 178 | GATEWAY4= # IPv4 address for this host 179 | PREFIX6= # IPv6 LAN address prefix for this host 180 | IID6=1 # IPv6 LAN ID for this host 181 | IPV6=0 # enable ipv6 182 | NO4=0 # no IPv4 Internet 183 | BANLAN=0 # ban clients from accessing private addresses 184 | DHCP_DNS=gateway # which ipv4 DNS the DHCP gives clients 185 | DHCP_DNS6=gateway # which ipv6 DNS the DHCP gives clients 186 | dnsmasq_NO_DNS=0 # disable dns server 187 | NO_DNSMASQ=0 # disable dnsmasq (dns and dhcp) 188 | CATCH_DNS=0 # catch clients 53 port packets 189 | SHOW_DNS_QUERY=0 # log dns 190 | ETC_HOSTS=0 191 | ADDN_HOSTS= 192 | DNS_NOCACHE= 193 | CONN_IFACE= # which interface user choose to use to create network 194 | INTERNET_IFACE= # which interface to get Internet from 195 | THISHOSTNAME= # this host's name the DNS tells clients 196 | TP_PORT= # transparent proxy port 197 | DNS= # upstream DNS 198 | MAC_USE_RANDOM=0 199 | NEW_MACADDR= 200 | DAEMONIZE=0 201 | 202 | # script variables 203 | SUBNET_IFACE= # which interface to create network 204 | SHARE_METHOD=nat 205 | OLD_MACADDR= 206 | SUBNET_NET4= 207 | SUBNET_NET6= 208 | 209 | 210 | ##### wifi hotspot 211 | # user options 212 | HIDDEN=0 # hidden wifi hotspot 213 | WIFI_IFACE= 214 | CHANNEL=default 215 | HOTSPOT20=0 # For enabling Hotspot 2.0 216 | WPA_VERSION=2 217 | MAC_FILTER=0 218 | MAC_FILTER_ACCEPT=/etc/hostapd/hostapd.accept 219 | DRIVER=nl80211 220 | NO_VIRT=0 # not use virtual interface 221 | COUNTRY= 222 | FREQ_BAND=2.4 223 | NO_HAVEGED=0 224 | HOSTAPD_DEBUG_ARGS= 225 | USE_PSK=0 226 | ISOLATE_CLIENTS=0 227 | QR=0 # show wifi qr 228 | STATIMEOUT= 229 | 230 | #wifi4 231 | IEEE80211N=0 232 | REQUIREHT=0 233 | HT_CAPAB='[HT40+]' 234 | #wifi5 235 | IEEE80211AC=0 236 | REQUIREVHT=0 237 | VHT_CAPAB= 238 | VHTCHANNELWIDTH=0 239 | VHTSEG0CHINDEX= 240 | VHTSEG1CHINDEX= 241 | #wifi6 242 | IEEE80211AX=0 243 | REQUIREHE=0 244 | HECHANNELWIDTH=0 245 | HESEG0CHINDEX= 246 | HESEG1CHINDEX= 247 | HESUBFE=0 248 | HESUBFR=0 249 | HEMUBFR=0 250 | P2PTWT=0 251 | 252 | # script variables 253 | PHY= 254 | VWIFI_IFACE= # virtual wifi interface name, if created 255 | VIRT_NAME= # name to use for virtual interface if --virt-name is used 256 | AP_IFACE= # can be VWIFI_IFACE or WIFI_IFACE 257 | USE_IWCONFIG=0 # some device can't use iw 258 | ####### 259 | 260 | #-- to deal with info of a running instance. then will exit 261 | LIST_RUNNING=0 262 | STOP_ID= 263 | LIST_CLIENTS_ID= 264 | 265 | # -- variables for running 266 | CONFDIR= 267 | IP_VERs= 268 | NM_UNM_LIST= # it's called "list" but for now one interface 269 | NM_PID= 270 | FIREWALLD_PID= 271 | OLD_FIREWALLD_ZONE= 272 | TMP_FIREWALLD_ZONE= 273 | KEEP_CONFDIR= 274 | } 275 | 276 | parse_user_options(){ 277 | while [[ -n "$1" ]]; do 278 | case "$1" in 279 | -h|--help) 280 | usage 281 | exit 0 282 | ;; 283 | --version) 284 | echo "$VERSION" 285 | exit 0 286 | ;; 287 | -i) 288 | shift 289 | CONN_IFACE="$1" 290 | shift 291 | ;; 292 | -o) 293 | shift 294 | INTERNET_IFACE="$1" 295 | shift 296 | ;; 297 | -n) 298 | shift 299 | SHARE_METHOD=none 300 | ;; 301 | --ban-priv) 302 | shift 303 | BANLAN=1 304 | ;; 305 | --tp) 306 | shift 307 | TP_PORT="$1" 308 | SHARE_METHOD=redsocks 309 | shift 310 | ;; 311 | -g) 312 | shift 313 | GATEWAY4="$1" 314 | shift 315 | ;; 316 | -6) 317 | shift 318 | IPV6=1 319 | ;; 320 | --no4) 321 | shift 322 | NO4=1 323 | ;; 324 | --p6) 325 | shift 326 | PREFIX6="$1" 327 | IPV6=1 328 | shift 329 | ;; 330 | --mac) 331 | shift 332 | NEW_MACADDR="$1" 333 | shift 334 | ;; 335 | --random-mac) 336 | shift 337 | MAC_USE_RANDOM=1 338 | ;; 339 | --dns) 340 | shift 341 | DNS="$1" 342 | shift 343 | ;; 344 | --no-dns) 345 | shift 346 | dnsmasq_NO_DNS=1 347 | ;; 348 | --no-dnsmasq) 349 | shift 350 | NO_DNSMASQ=1 351 | ;; 352 | --dhcp-dns) 353 | shift 354 | DHCP_DNS="$1" 355 | shift 356 | ;; 357 | --dhcp-dns6) 358 | shift 359 | DHCP_DNS6="$1" 360 | shift 361 | ;; 362 | --catch-dns) 363 | shift 364 | CATCH_DNS=1 365 | ;; 366 | --log-dns) 367 | shift 368 | SHOW_DNS_QUERY=1 369 | ;; 370 | --hostname) 371 | shift 372 | THISHOSTNAME="$1" 373 | shift 374 | ;; 375 | -d) 376 | shift 377 | ETC_HOSTS=1 378 | ;; 379 | -e) 380 | shift 381 | ADDN_HOSTS="$1" 382 | shift 383 | ;; 384 | --dns-nocache) 385 | shift 386 | DNS_NOCACHE=1 387 | ;; 388 | --isolate-clients) 389 | shift 390 | ISOLATE_CLIENTS=1 391 | ;; 392 | # wifi ap 393 | --ap) 394 | shift 395 | WIFI_IFACE="$1" 396 | shift 397 | SSID="$1" 398 | shift 399 | ;; 400 | -p|--password) 401 | shift 402 | PASSPHRASE="$1" 403 | shift 404 | ;; 405 | --qr) 406 | shift 407 | QR=1 408 | ;; 409 | --hidden) 410 | shift 411 | HIDDEN=1 412 | ;; 413 | --mac-filter) 414 | shift 415 | MAC_FILTER=1 416 | ;; 417 | --mac-filter-accept) 418 | shift 419 | MAC_FILTER_ACCEPT="$1" 420 | shift 421 | ;; 422 | -c) 423 | shift 424 | CHANNEL="$1" 425 | shift 426 | ;; 427 | --hs20) 428 | shift 429 | HOTSPOT20=1 430 | ;; 431 | -w) 432 | shift 433 | WPA_VERSION="$1" 434 | [[ "$WPA_VERSION" == "2+1" ]] && WPA_VERSION=1+2 435 | shift 436 | ;; 437 | --sta-timeout) 438 | shift 439 | STATIMEOUT="$1" 440 | shift 441 | ;; 442 | --driver) 443 | shift 444 | DRIVER="$1" 445 | shift 446 | ;; 447 | --no-virt) 448 | shift 449 | NO_VIRT=1 450 | ;; 451 | --virt-name) 452 | shift 453 | VIRT_NAME="$1" 454 | shift 455 | ;; 456 | --country) 457 | shift 458 | COUNTRY="$1" 459 | shift 460 | ;; 461 | --freq-band) 462 | shift 463 | FREQ_BAND="$1" 464 | shift 465 | ;; 466 | --no-haveged) 467 | shift 468 | NO_HAVEGED=1 469 | ;; 470 | --hostapd-debug) 471 | shift 472 | if [ "$1" = "1" ]; then 473 | HOSTAPD_DEBUG_ARGS="-d" 474 | elif [ "$1" = "2" ]; then 475 | HOSTAPD_DEBUG_ARGS="-dd" 476 | else 477 | printf "Error: argument for --hostapd-debug expected 1 or 2, got %s\n" "$1" 478 | exit 1 479 | fi 480 | shift 481 | ;; 482 | --psk) 483 | shift 484 | USE_PSK=1 485 | ;; 486 | # wifi 4 487 | --wifi4|--ieee80211n) 488 | shift 489 | IEEE80211N=1 490 | ;; 491 | --req-wifi4|--req-ht|--require-ht) 492 | shift 493 | REQUIREHT=1 494 | ;; 495 | --ht-capab) 496 | shift 497 | HT_CAPAB="$1" 498 | shift 499 | ;; 500 | # wifi 5 501 | --wifi5|--ieee80211ac) 502 | shift 503 | IEEE80211AC=1 504 | ;; 505 | --req-wifi5|--req-vht|--require-vht) 506 | shift 507 | REQUIREVHT=1 508 | ;; 509 | --vht-capab) 510 | shift 511 | VHT_CAPAB="$1" 512 | shift 513 | ;; 514 | --vht-ch-width|--vht-channel-width) 515 | shift 516 | VHTCHANNELWIDTH="$1" 517 | shift 518 | ;; 519 | --vht-seg0-ch|--vht-seg0-channel) 520 | shift 521 | VHTSEG0CHINDEX="$1" 522 | shift 523 | ;; 524 | --vht-seg1-ch|--vht-seg1-channel) 525 | shift 526 | VHTSEG1CHINDEX="$1" 527 | shift 528 | ;; 529 | # wifi 6 530 | --wifi6|--ieee80211ax) 531 | shift 532 | IEEE80211AX=1 533 | ;; 534 | --req-wifi6|--req-he|--require-he) 535 | shift 536 | REQUIREHE=1 537 | ;; 538 | --he-ch-width|--he-channel-width) 539 | shift 540 | HECHANNELWIDTH="$1" 541 | shift 542 | ;; 543 | --he-seg0-ch|--he-seg0-channel) 544 | shift 545 | HESEG0CHINDEX="$1" 546 | shift 547 | ;; 548 | --he-seg1-ch|--he-seg1-channel) 549 | shift 550 | HESEG1CHINDEX="$1" 551 | shift 552 | ;; 553 | --he-su-bfe) 554 | shift 555 | HESUBFE=1 556 | ;; 557 | --he-su-bfr) 558 | shift 559 | HESUBFR=1 560 | ;; 561 | --he-mu-bfr) 562 | shift 563 | HEMUBFR=1 564 | ;; 565 | --p2ptwt) 566 | shift 567 | P2PTWT=1 568 | ;; 569 | # instance managing 570 | --daemon) 571 | shift 572 | DAEMONIZE=1 573 | ;; 574 | --stop) 575 | shift 576 | STOP_ID="$1" 577 | shift 578 | ;; 579 | -l|--list-running) 580 | shift 581 | LIST_RUNNING=1 582 | ;; 583 | --lc|--list-clients) 584 | shift 585 | LIST_CLIENTS_ID="$1" 586 | shift 587 | ;; 588 | --keep-confdir) 589 | shift 590 | KEEP_CONFDIR=1 591 | ;; 592 | *) 593 | echo "Invalid parameter: $1" 1>&2 594 | exit 1 595 | ;; 596 | esac 597 | done 598 | } 599 | 600 | 601 | # seperate ip and port 602 | sep_ip_port() { 603 | # usage: sep_ip_port 604 | # input can be: 605 | # port (ip is 127.0.0.1) 606 | # ipv4 607 | # [ipv6] 608 | # ipv4:port 609 | # [ipv6]:port 610 | local IP 611 | local PORT 612 | local INPUT 613 | INPUT="$1" 614 | if (echo "$INPUT" | grep '\.' >/dev/null 2>&1) ;then 615 | if (echo "$INPUT" | grep ':' >/dev/null 2>&1) ;then 616 | # ipv4 + port 617 | IP="$(echo "$INPUT" | cut -d: -f1)" 618 | PORT="$(echo "$INPUT" | cut -d: -f2)" 619 | else 620 | # ipv4 621 | IP="$INPUT" 622 | fi 623 | elif (echo "$INPUT" | grep '\]' >/dev/null 2>&1) ;then 624 | if (echo "$INPUT" | grep '\]\:' >/dev/null 2>&1) ;then 625 | # ipv6 + port 626 | IP="$(echo "$INPUT" | cut -d']' -f1 | cut -d'[' -f2)" 627 | PORT="$(echo "$INPUT" | cut -d']' -f2 |cut -d: -f2)" 628 | else 629 | # ipv6 630 | IP="$(echo "$INPUT" | cut -d']' -f1 | cut -d'[' -f2)" 631 | fi 632 | else 633 | # port 634 | IP='127.0.0.1' 635 | PORT="$INPUT" 636 | fi 637 | printf -v "$2" %s "$IP" 638 | printf -v "$3" %s "$PORT" 639 | } 640 | 641 | #========================= 642 | is_interface() { 643 | [[ -z "$1" ]] && return 1 644 | [[ -d "/sys/class/net/${1}" ]] 645 | } 646 | 647 | is_vface_name_allocated(){ 648 | is_interface "$1" || [[ -f "$COMMON_CONFDIR/vfaces/${1}" ]] 649 | } 650 | 651 | get_interface_phy_device() { # only for wifi interface 652 | local x 653 | for x in /sys/class/ieee80211/*; do 654 | [[ ! -e "$x" ]] && continue 655 | if [[ "${x##*/}" = "$1" ]]; then 656 | echo "$1" 657 | return 0 658 | elif [[ -e "$x/device/net/$1" ]]; then 659 | echo "${x##*/}" 660 | return 0 661 | elif [[ -e "$x/device/net:$1" ]]; then 662 | echo "${x##*/}" 663 | return 0 664 | fi 665 | done 666 | return 1 667 | } 668 | 669 | get_adapter_info() { # only for wifi interface 670 | local iPHY 671 | iPHY=$(get_interface_phy_device "$1") 672 | [[ $? -ne 0 ]] && return 1 673 | iw phy "$iPHY" info 674 | } 675 | 676 | get_adapter_kernel_module() { 677 | local MODULE 678 | MODULE=$(readlink -f "/sys/class/net/$1/device/driver/module") 679 | echo "${MODULE##*/}" 680 | } 681 | 682 | can_be_sta_and_ap() { 683 | # iwconfig does not provide this information, assume false 684 | [[ $USE_IWCONFIG -eq 1 ]] && return 1 685 | if [[ "$(get_adapter_kernel_module "$1")" == "brcmfmac" ]]; then 686 | echo "WARN: brmfmac driver doesn't work properly with virtual interfaces and" >&2 687 | echo " it can cause kernel panic. For this reason we disallow virtual" >&2 688 | echo " interfaces for your adapter." >&2 689 | echo " For more info: https://github.com/oblique/create_ap/issues/203" >&2 690 | return 1 691 | fi 692 | get_adapter_info "$1" | grep -E '{.* managed.* AP.*}' > /dev/null 2>&1 && return 0 693 | get_adapter_info "$1" | grep -E '{.* AP.* managed.*}' > /dev/null 2>&1 && return 0 694 | return 1 695 | } 696 | 697 | can_be_ap() { 698 | # iwconfig does not provide this information, assume true 699 | [[ $USE_IWCONFIG -eq 1 ]] && return 0 700 | get_adapter_info "$1" | grep -E '\* AP$' > /dev/null 2>&1 && return 0 701 | return 1 702 | } 703 | 704 | can_transmit_to_channel() { 705 | local IFACE CHANNEL_NUM CHANNEL_INFO CHANNEL_FREQ_FILTER 706 | IFACE=$1 707 | CHANNEL_NUM=$2 708 | if [[ $FREQ_BAND == "2.4" ]]; then 709 | CHANNEL_FREQ_FILTER="(24)" 710 | elif [[ $FREQ_BAND -eq 5 ]]; then 711 | CHANNEL_FREQ_FILTER="(5[1-8])" 712 | elif [[ $FREQ_BAND -eq 6 ]]; then 713 | CHANNEL_FREQ_FILTER="((59)|(6[0-9])|(7[0-1]))" 714 | fi 715 | 716 | if [[ $USE_IWCONFIG -eq 0 ]]; then 717 | CHANNEL_INFO=$(get_adapter_info "${IFACE}" | grep -E " ${CHANNEL_FREQ_FILTER}[0-9]{2}(\.[0-9]+){0,1} MHz \[${CHANNEL_NUM}\]") 718 | [[ -z "${CHANNEL_INFO}" ]] && return 1 719 | [[ "${CHANNEL_INFO}" == *no\ IR* ]] && return 2 720 | [[ "${CHANNEL_INFO}" == *disabled* ]] && return 3 721 | return 0 722 | else 723 | CHANNEL_NUM="$(printf '%02d' "${CHANNEL_NUM}")" 724 | CHANNEL_INFO=$(iwlist "${IFACE}" channel | grep -E "Channel[[:blank:]]${CHANNEL_NUM}[[:blank:]]?:") 725 | [[ -z "${CHANNEL_INFO}" ]] && return 1 726 | return 0 727 | fi 728 | } 729 | 730 | ieee80211_frequency_to_channel() { 731 | local FREQ=$1 732 | 733 | # 2.4G 734 | if [[ $FREQ -ge 2412 && $FREQ -le 2472 ]]; then # 2.4 GHz band: Channels 1-13 (2412~2472 MHz) 735 | echo $(( (FREQ - 2407) / 5 )) 736 | elif [[ $FREQ -eq 2484 ]]; then # 2.4 GHz Channel 14 (2484 MHz, Japan only) 737 | echo 14 738 | 739 | # 5G 740 | elif [[ $FREQ -ge 5160 && $FREQ -le 5885 ]]; then # 5 GHz band: Standard Channels 36-165 (5180~5825 MHz) (extra: 32, 169-177) 741 | echo $(( (FREQ - 5000) / 5 )) 742 | 743 | # 6G 744 | elif [[ $FREQ -ge 5955 && $FREQ -le 7115 ]]; then # 6 GHz band: Channels 1-233 (5955~7115 MHz), Wi-Fi 6E/7 745 | echo $(( (FREQ - 5950) / 5 )) 746 | elif [[ $FREQ -eq 5935 ]]; then # 6 GHz band: Special case for 5935 MHz (Channel 2, rare) 747 | echo 2 748 | 749 | else # Frequency not in supported Wi-Fi bands (2.4/5/6 GHz) 750 | echo 0 751 | fi 752 | } 753 | 754 | 755 | is_interface_wifi_connected() { 756 | if [[ $USE_IWCONFIG -eq 0 ]]; then 757 | iw dev "$1" link 2>&1 | grep -E '^Connected to' > /dev/null 2>&1 && return 0 758 | else 759 | iwconfig "$1" 2>&1 | grep -E 'Access Point: [0-9a-fA-F]{2}:' > /dev/null 2>&1 && return 0 760 | fi 761 | return 1 762 | } 763 | 764 | 765 | is_unicast_macaddr() { 766 | local x 767 | x=$(echo "$1" | cut -d: -f1) 768 | x=$(printf '%d' "0x${x}") 769 | [[ $(expr "$x" % 2) -eq 0 ]] 770 | } 771 | 772 | get_interface_mac() { 773 | is_interface "$1" || return 774 | cat "/sys/class/net/${1}/address" 775 | } 776 | 777 | show_interface_pci_info() { # pci id / model / virtual 778 | is_interface "$1" || return 779 | 780 | local device_path 781 | local bus_id="" 782 | local device_type_and_bus_id="unknown" 783 | local driver="" 784 | local device_fullname="" 785 | 786 | device_path="$(readlink -f /sys/class/net/$1)" 787 | 788 | if [[ "$device_path" == "/sys/devices/pci"* ]]; then 789 | local pci_path 790 | 791 | pci_path=$device_path/../.. 792 | 793 | if [[ -d "$pci_path/driver" ]] ; then 794 | driver=$(readlink -f "$pci_path/driver" | sed 's/\//\n/g' | tail -n 1) 795 | fi 796 | 797 | bus_id="$(echo "$device_path" | sed 's/\//\n/g' | tail -n 3 |sed -n 1p)" 798 | device_type_and_bus_id="PCI: $bus_id" 799 | 800 | if which lspci >/dev/null 2>&1 ; then 801 | device_fullname="$( lspci -D -nn -s "$bus_id" | awk '{$1="" ; print $0}' )" 802 | fi 803 | 804 | elif [[ "$device_path" == *"/virtual/"* ]]; then 805 | device_type_and_bus_id="virtual interface" 806 | fi 807 | 808 | echo "$device_type_and_bus_id" 809 | [[ -n "$driver" ]] && echo "System-already-loaded driver: $driver" 810 | [[ -n "$device_fullname" ]] && echo "$device_fullname" 811 | echo "" 812 | # TODO Fix pci and usb devices 813 | } 814 | 815 | alloc_new_vface_name() { # only for wifi 816 | local i=0 817 | local v_iface_name="$VIRT_NAME" 818 | if [[ -z $VIRT_NAME ]]; then 819 | while :; do 820 | v_iface_name="x$i${WIFI_IFACE}" 821 | i=$((i + 1)) 822 | is_vface_name_allocated "${v_iface_name}" || break 823 | done 824 | fi 825 | mkdir -p "$COMMON_CONFDIR/vfaces" 826 | touch "$COMMON_CONFDIR/vfaces/${v_iface_name}" 827 | echo "${v_iface_name}" 828 | } 829 | 830 | dealloc_vface_name() { 831 | rm -f "$COMMON_CONFDIR/vfaces/$1" 832 | } 833 | 834 | #====== 835 | 836 | get_all_mac_in_system() { 837 | cat /sys/class/net/*/address 838 | } 839 | 840 | get_new_macaddr_according_to_existing() { 841 | local REALDEV OLDMAC NEWMAC LAST_BYTE i 842 | REALDEV=$1 843 | OLDMAC=$(get_interface_mac "$REALDEV") 844 | NEWMAC="" 845 | LAST_BYTE=$(printf %d 0x${OLDMAC##*:}) 846 | for i in {10..240}; do 847 | NEWMAC="${OLDMAC%:*}:$(printf %02x $(( ($LAST_BYTE + $i) % 256 )))" 848 | (get_all_mac_in_system | grep "$NEWMAC" > /dev/null 2>&1) || break 849 | done 850 | echo "$NEWMAC" 851 | } 852 | 853 | generate_random_mac() { 854 | local r1 r2 r3 r4 r5 r6 855 | local RAND_MAC 856 | while :; do 857 | r1=$( printf "%02x" $(($RANDOM%256/4*4)) ) 858 | r2=$( printf "%02x" $(($RANDOM%256)) ) 859 | r3=$( printf "%02x" $(($RANDOM%256)) ) 860 | r4=$( printf "%02x" $(($RANDOM%256)) ) 861 | r5=$( printf "%02x" $(($RANDOM%256)) ) 862 | r6=$( printf "%02x" $(($RANDOM%256)) ) 863 | RAND_MAC="$r1:$r2:$r3:$r4:$r5:$r6" 864 | ( ! ip link | grep "link" | grep "$RAND_MAC" > /dev/null 2>&1 ) && \ 865 | ( ! ip maddress | grep "link" | grep "$RAND_MAC" > /dev/null 2>&1 ) && \ 866 | ( ! ip neigh | grep "lladdr $RAND_MAC" > /dev/null 2>&1 ) && \ 867 | ( ! get_all_mac_in_system | grep "$RAND_MAC" ) && \ 868 | break 869 | done 870 | echo "$RAND_MAC" 871 | } 872 | 873 | 874 | is_ip4_lan_range_available() { # checks 192.168.x.x 875 | ( ip -4 address | grep "inet 192\.168\.$1\." > /dev/null 2>&1 ) && return 1 876 | ( ip -4 route | grep "^192\.168\.$1\." > /dev/null 2>&1 ) && return 1 877 | ( ip -4 route get "192.168.$1.0" 2>&1 | grep -E "\bvia\b|\bunreachable\b" > /dev/null 2>&1 ) && \ 878 | ( ip -4 route get "192.168.$1.255" 2>&1 | grep -E "\bvia\b|\bunreachable\b" > /dev/null 2>&1 ) && return 0 879 | return 1 880 | } 881 | is_ip6_lan_range_available() { # checks fdxx:: 882 | ( ip -6 address | grep -i "inet6 fd$1:$2$3:$4$5:$6$7:" > /dev/null 2>&1 ) && return 1 883 | ( ip -6 route | grep -i "^fd$1:$2$3:$4$5:$6$7:" > /dev/null 2>&1 ) && return 1 884 | ( ip -6 route get "fd$1:$2$3:$4$5:$6$7::" 2>&1 | grep -E "\bvia\b|\bunreachable\b" > /dev/null 2>&1 ) && \ 885 | ( ip -6 route get "fd$1:$2$3:$4$5:$6$7:ffff:ffff:ffff:ffff" 2>&1 | grep -E "\bvia\b|\bunreachable\b" > /dev/null 2>&1 ) && return 0 886 | return 1 887 | } 888 | 889 | generate_random_ip4() { 890 | local random_ip4 891 | while :; do 892 | random_ip4=$(($RANDOM%256)) 893 | is_ip4_lan_range_available $random_ip4 && break 894 | done 895 | echo "192.168.$random_ip4.1" 896 | } 897 | generate_random_lan_ip6_prefix() { 898 | local r1 r2 r3 r4 r5 r6 r7 899 | while :; do 900 | r1=$( printf "%x" $(($RANDOM%240+16)) ) 901 | r2=$( printf "%x" $(($RANDOM%240+16)) ) 902 | r3=$( printf "%x" $(($RANDOM%240+16)) ) 903 | r4=$( printf "%x" $(($RANDOM%240+16)) ) 904 | r5=$( printf "%x" $(($RANDOM%240+16)) ) 905 | r6=$( printf "%x" $(($RANDOM%240+16)) ) 906 | r7=$( printf "%x" $(($RANDOM%240+16)) ) 907 | is_ip6_lan_range_available "$r1" "$r2" "$r3" "$r4" "$r5" "$r6" "$r7" && break 908 | done 909 | echo "fd$r1:$r2$r3:$r4$r5:$r6$r7::" 910 | } 911 | 912 | 913 | 914 | # start haveged when needed 915 | haveged_watchdog() { 916 | local show_warn=1 917 | while :; do 918 | if [[ $(cat /proc/sys/kernel/random/entropy_avail) -lt 1000 ]]; then 919 | if ! which haveged > /dev/null 2>&1; then 920 | if [[ $show_warn -eq 1 ]]; then 921 | echo "WARN: Low entropy detected. We recommend you to install \`haveged'" 1>&2 922 | show_warn=0 923 | fi 924 | elif ! pidof haveged > /dev/null 2>&1; then # TODO judge zombie ? 925 | echo "Low entropy detected, starting haveged" 1>&2 926 | # boost low-entropy 927 | haveged -w 1024 -p "$COMMON_CONFDIR/haveged.pid" 928 | fi 929 | fi 930 | sleep 2 931 | done 932 | } 933 | pid_watchdog() { 934 | local PID="$1" 935 | local SLEEP="$2" 936 | local ERR_MSG="$3" 937 | local ST 938 | while true 939 | do 940 | if [[ -e "/proc/$PID" ]]; then 941 | ST="$(cat "/proc/$PID/status" | grep "^State:" | awk '{print $2}')" 942 | if [[ "$ST" != 'Z' ]]; then 943 | sleep "$SLEEP" 944 | continue 945 | fi 946 | fi 947 | die "$ERR_MSG" 948 | done 949 | 950 | } 951 | #======== 952 | get_pid_by_dbus_name() { 953 | local DBUS_NAME="$1" 954 | local pid r 955 | 956 | which dbus-send >/dev/null 2>&1 || return 1 957 | 958 | pid="$( dbus-send --system --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.GetConnectionUnixProcessID string:$DBUS_NAME 2>/dev/null | grep " uint32 " | awk '{print $2}' )" 959 | r=$? 960 | 961 | echo "$pid" 962 | return $r 963 | } 964 | is_same_netns() { 965 | local pid2="$1" 966 | local my_netns his_netns 967 | [[ ! -f /proc/$$/ns/net ]] && return 0 # no netns feature. treat as same 968 | my_netns="$(readlink "/proc/$$/ns/net")" 969 | his_netns="$(readlink "/proc/$pid2/ns/net")" 970 | [[ ! -n "$his_netns" ]] && return 1 # can't find his pid or netns (maybe different pidns), treat as not same 971 | [[ "$my_netns" == "$his_netns" ]] && return 0 972 | return 1 973 | } 974 | #----------------- 975 | # only support NetworkManager >= 0.9.9 976 | is_nm_running() { 977 | NM_PID="$(get_pid_by_dbus_name "org.freedesktop.NetworkManager")" 978 | 979 | [[ ! -n "$NM_PID" ]] && return 1 # not running 980 | 981 | if (which nmcli >/dev/null 2>&1 ) && (nmcli -t -f RUNNING g 2>&1 | grep -E '^running$' >/dev/null 2>&1 ) ; then 982 | if is_same_netns "$NM_PID"; then 983 | return 0 984 | fi 985 | fi 986 | 987 | NM_PID= # cancel value if treat as not running 988 | return 1 # not running 989 | } 990 | 991 | nm_knows() { 992 | (nmcli dev show "$1" | grep -E "^GENERAL.STATE:" >/dev/null 2>&1 ) && return 0 # nm sees 993 | return 1 # nm doesn't see this interface 994 | } 995 | nm_get_manage() { # get an interface's managed state 996 | local s 997 | s=$(nmcli dev show "$1" | grep -E "^GENERAL.STATE:") || return 2 # no such interface 998 | (echo "$s" | grep "unmanaged" >/dev/null 2>&1) && return 1 # unmanaged 999 | return 0 # managed 1000 | } 1001 | nm_set_unmanaged() { 1002 | while ! nm_knows "$1" ; do # wait for virtual wifi interface seen by NM 1003 | sleep 0.5 1004 | done 1005 | if nm_get_manage "$1" ;then 1006 | echo "Set $1 unmanaged by NetworkManager" 1007 | nmcli dev set "$1" managed no || die "Failed to set $1 unmanaged by NetworkManager" 1008 | NM_UNM_LIST=$1 1009 | sleep 1 1010 | fi 1011 | } 1012 | 1013 | nm_set_managed() { 1014 | nmcli dev set "$1" managed yes 1015 | NM_UNM_LIST= 1016 | } 1017 | nm_restore_manage() { 1018 | if [[ -n "$NM_UNM_LIST" ]]; then 1019 | echo "Restore $NM_UNM_LIST managed by NetworkManager" 1020 | nm_set_managed "$NM_UNM_LIST" 1021 | sleep 0.5 1022 | fi 1023 | } 1024 | #------- 1025 | is_firewalld_running() { 1026 | FIREWALLD_PID="$(get_pid_by_dbus_name "org.fedoraproject.FirewallD1")" 1027 | 1028 | [[ ! -n "$FIREWALLD_PID" ]] && return 1 # not running 1029 | 1030 | if (which firewall-cmd >/dev/null 2>&1 ) && [[ "$(firewall-cmd --state 2>&1)" == "running" ]] ; then 1031 | if is_same_netns "$FIREWALLD_PID"; then 1032 | echo "firewalld is running ($(firewall-cmd --version))" 1033 | return 0 1034 | fi 1035 | fi 1036 | 1037 | FIREWALLD_PID= # cancel value if treat as not running 1038 | return 1 # not running 1039 | } 1040 | firewalld_addto_tmptrustedzone() { 1041 | OLD_FIREWALLD_ZONE="$(firewall-cmd --get-zone-of-interface=$SUBNET_IFACE 2>/dev/null)" 1042 | [[ "$OLD_FIREWALLD_ZONE" == 'trusted' ]] && return 1043 | 1044 | TMP_FIREWALLD_ZONE="trusted" # need subnet interface into this zone during linux-router working 1045 | if [[ -n "$OLD_FIREWALLD_ZONE" ]]; then 1046 | echo "Getting $SUBNET_IFACE out from firewalld zone '$OLD_FIREWALLD_ZONE' ..." 1047 | firewall-cmd --zone=$OLD_FIREWALLD_ZONE --remove-interface=$SUBNET_IFACE >/dev/null || die "Failed removing $SUBNET_IFACE from firewalld '$OLD_FIREWALLD_ZONE' zone" 1048 | fi 1049 | echo "Adding $SUBNET_IFACE to firewalld '$TMP_FIREWALLD_ZONE' zone" 1050 | firewall-cmd --zone=$TMP_FIREWALLD_ZONE --add-interface=$SUBNET_IFACE >/dev/null || die "Failed adding interface to firewalld temporary '$TMP_FIREWALLD_ZONE' zone" 1051 | 1052 | } 1053 | firewalld_restoreoldzone() { 1054 | if [[ -n "$TMP_FIREWALLD_ZONE" ]];then 1055 | echo "Removing $SUBNET_IFACE from firewalld '$TMP_FIREWALLD_ZONE' zone" 1056 | firewall-cmd --zone=$TMP_FIREWALLD_ZONE --remove-interface=$SUBNET_IFACE >/dev/null 1057 | 1058 | if [[ -n "$OLD_FIREWALLD_ZONE" ]]; then 1059 | echo "Restoring $SUBNET_IFACE to firewalld '$OLD_FIREWALLD_ZONE' zone" 1060 | firewall-cmd --zone=$OLD_FIREWALLD_ZONE --add-interface=$SUBNET_IFACE >/dev/null 1061 | fi 1062 | fi 1063 | } 1064 | 1065 | #========= 1066 | CUSTOM_CHAINS_4_filter= 1067 | CUSTOM_CHAINS_4_nat= 1068 | CUSTOM_CHAINS_6_filter= 1069 | CUSTOM_CHAINS_6_nat= 1070 | iptb() 1071 | { 1072 | local FoS=$1 # 4 | 6 1073 | shift 1074 | local Vis=$1 # 'v' | 'n' 1075 | shift 1076 | local T=$1 # table 1077 | shift 1078 | local ACT=$1 # action: I | A | N . On undo: I or A -> D , N -> F+X 1079 | shift 1080 | local CH=$1 # chain 1081 | shift 1082 | 1083 | [[ "$IPV6" -ne 1 && "$FoS" == "6" ]] && return 1084 | 1085 | local CMD_HEAD="" 1086 | local MOUTH="" 1087 | local NECK="" 1088 | local HAND_UN_NC=0 1089 | local TAIL="" 1090 | 1091 | local FULL="" 1092 | local ADD_TO_UNDO=1 1093 | 1094 | local arr_name w 1095 | 1096 | for arr_name in CUSTOM_CHAINS_4_filter CUSTOM_CHAINS_4_nat CUSTOM_CHAINS_6_filter CUSTOM_CHAINS_6_nat 1097 | do 1098 | local arr_content 1099 | eval arr_content=\"\${$arr_name}\" 1100 | #echo $arr_content 1101 | 1102 | for w in $arr_content 1103 | do 1104 | if [[ "$arr_name" =~ "$FoS" && "$arr_name" =~ "$T" && "$w" == "$CH" ]]; then 1105 | ADD_TO_UNDO=0 1106 | fi 1107 | done 1108 | done 1109 | 1110 | 1111 | [[ "$FoS" == "4" ]] && CMD_HEAD="iptables -w " 1112 | [[ "$FoS" == "6" ]] && CMD_HEAD="ip6tables -w " 1113 | 1114 | [[ "$Vis" == 'v' ]] && MOUTH="-v" 1115 | 1116 | NECK="-t ${T}" 1117 | 1118 | if [[ "$ACT" == "N" ]]; then 1119 | eval CUSTOM_CHAINS_${FoS}_${T}=\"\${CUSTOM_CHAINS_${FoS}_${T}} ${CH}\" 1120 | HAND_UN_NC=1 1121 | fi 1122 | 1123 | 1124 | 1125 | [[ ! "$NETFILTER_XT_MATCH_COMMENT" == "0" ]] && TAIL="-m comment --comment lrt${$}${SUBNET_IFACE}" 1126 | 1127 | if [[ "$ADD_TO_UNDO" -eq 1 ]]; then 1128 | if [[ "$ACT" == "I" || "$ACT" == "A" ]]; then 1129 | echo "$CMD_HEAD $NECK -D ${CH} $@ $TAIL" >> $CONFDIR/undo_iptables.sh 1130 | fi 1131 | 1132 | if [[ "$HAND_UN_NC" -eq 1 ]]; then 1133 | echo "$CMD_HEAD $NECK -F ${CH} $@ $TAIL" >> $CONFDIR/undo_iptables_2.sh 1134 | echo "$CMD_HEAD $NECK -X ${CH} $@ $TAIL" >> $CONFDIR/undo_iptables_2.sh 1135 | fi 1136 | fi 1137 | 1138 | 1139 | 1140 | 1141 | FULL="$CMD_HEAD $MOUTH $NECK -${ACT} ${CH} $@ $TAIL" 1142 | #echo $FULL 1143 | $FULL 1144 | return $? 1145 | } 1146 | 1147 | disable_unwanted_forwarding() { 1148 | for iv in "${IP_VERs[@]}"; do 1149 | if [[ "$INTERNET_IFACE" ]]; then 1150 | iptb "$iv" n filter I FORWARD \ 1151 | -i "$SUBNET_IFACE" ! -o "$INTERNET_IFACE" \ 1152 | -j REJECT || die 1153 | iptb "$iv" n filter I FORWARD \ 1154 | ! -i "$INTERNET_IFACE" -o "$SUBNET_IFACE" \ 1155 | -j REJECT || die 1156 | fi 1157 | 1158 | if [[ "$SHARE_METHOD" == 'redsocks' || "$SHARE_METHOD" == 'none' \ 1159 | || ( "$iv" -eq "4" && "$NO4" -eq 1 ) ]];then 1160 | iptb "$iv" n filter I FORWARD -i "$SUBNET_IFACE" -j REJECT || die 1161 | iptb "$iv" n filter I FORWARD -o "$SUBNET_IFACE" -j REJECT || die 1162 | fi 1163 | done 1164 | 1165 | } 1166 | start_nat() { 1167 | local SUBNET_NET 1168 | 1169 | local iv 1170 | 1171 | echo 1172 | echo "iptables: NAT " 1173 | 1174 | for iv in "${IP_VERs[@]}"; do 1175 | [[ "$iv" -eq "4" && ! $NO4 -eq 0 ]] && continue 1176 | 1177 | [[ "$iv" -eq "4" ]] && SUBNET_NET="$SUBNET_NET4" 1178 | [[ "$iv" -eq "6" ]] && SUBNET_NET="$SUBNET_NET6" 1179 | 1180 | if [[ -n "$INTERNET_IFACE" ]]; then # only one Internet interface 1181 | # masquerade subnet -> internet 1182 | iptb "$iv" v nat I POSTROUTING -s "$SUBNET_NET" ! -d "$SUBNET_NET" \ 1183 | -o "$INTERNET_IFACE" \ 1184 | -j MASQUERADE || die 1185 | 1186 | # forward subnet -> internet 1187 | iptb "$iv" v filter I FORWARD -i "$SUBNET_IFACE" -s "$SUBNET_NET" \ 1188 | -o "$INTERNET_IFACE" \ 1189 | -j ACCEPT || die 1190 | 1191 | # forward any -> subnet 1192 | iptb "$iv" v filter I FORWARD -o "$SUBNET_IFACE" -d "$SUBNET_NET" \ 1193 | -i "$INTERNET_IFACE" \ 1194 | -j ACCEPT || die 1195 | else # any interface can be Internet 1196 | # masquerade subnet -> any(!subnet) 1197 | iptb "$iv" v nat I POSTROUTING -s "$SUBNET_NET" ! -d "$SUBNET_NET" \ 1198 | ! -o "$SUBNET_IFACE" \ 1199 | -j MASQUERADE || die 1200 | 1201 | # forward subnet -> any 1202 | iptb "$iv" v filter I FORWARD -i "$SUBNET_IFACE" -s "$SUBNET_NET" \ 1203 | -j ACCEPT || die 1204 | 1205 | # forward any -> subnet 1206 | iptb "$iv" v filter I FORWARD -o "$SUBNET_IFACE" -d "$SUBNET_NET" \ 1207 | -j ACCEPT || die 1208 | fi 1209 | done 1210 | } 1211 | 1212 | start_ban_lan() { 1213 | local arr_nets_to_protect 1214 | local ICMP_NAME 1215 | local iv s 1216 | 1217 | echo 1218 | echo "iptables: Disallow clients to access LAN" 1219 | 1220 | for iv in "${IP_VERs[@]}"; do 1221 | # ban forwarding for subnet 1222 | iptb "$iv" n filter N lrt${$}${SUBNET_IFACE}-BLF || die 1223 | # TODO: allow '--dhcp-dns(6)' address port 53, which can be something needed, e.g. a VPN's internal private IP 1224 | if [[ "$iv" -eq "4" ]]; then 1225 | arr_nets_to_protect=("0.0.0.0/8" "10.0.0.0/8" "100.64.0.0/10" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12" "192.168.0.0/16" "224.0.0.0/4" "255.255.255.255") 1226 | ICMP_NAME="icmp" 1227 | elif [[ "$iv" -eq "6" ]]; then 1228 | arr_nets_to_protect=("fc00::/7" "fe80::/10" "ff00::/8" "::1" "::/128" "::ffff:0:0/96" "::ffff:0:0:0/96") 1229 | ICMP_NAME="icmpv6" 1230 | fi 1231 | for s in "${arr_nets_to_protect[@]}"; do 1232 | iptb "$iv" v filter I lrt${$}${SUBNET_IFACE}-BLF -d "$s" -j REJECT || die 1233 | done 1234 | iptb "$iv" n filter I FORWARD -i ${SUBNET_IFACE} -j lrt${$}${SUBNET_IFACE}-BLF || die 1235 | 1236 | # ban input from subnet 1237 | iptb "$iv" n filter N lrt${$}${SUBNET_IFACE}-BLI || die 1238 | iptb "$iv" v filter I lrt${$}${SUBNET_IFACE}-BLI -i ${SUBNET_IFACE} ! -p "$ICMP_NAME" -j REJECT || die # ipv6 need icmp to function. TODO: maybe we can block some unneeded icmp to improve security 1239 | iptb "$iv" n filter I INPUT -i ${SUBNET_IFACE} -j lrt${$}${SUBNET_IFACE}-BLI || die 1240 | done 1241 | 1242 | } 1243 | 1244 | allow_dns_port() { 1245 | local SUBNET_NET 1246 | local GATEWAY 1247 | local PROTs 1248 | local iv pt 1249 | 1250 | 1251 | echo 1252 | echo "iptables: allow DNS" 1253 | 1254 | for iv in "${IP_VERs[@]}"; do 1255 | [[ "$iv" -eq "4" ]] && GATEWAY="$GATEWAY4" 1256 | [[ "$iv" -eq "6" ]] && GATEWAY="$GATEWAY6" 1257 | 1258 | [[ "$iv" -eq "4" ]] && SUBNET_NET="$SUBNET_NET4" 1259 | [[ "$iv" -eq "6" ]] && SUBNET_NET="$SUBNET_NET6" 1260 | 1261 | 1262 | PROTs=("tcp" "udp") 1263 | for pt in "${PROTs[@]}"; do 1264 | iptb "$iv" v filter I INPUT -i "$SUBNET_IFACE" -s "$SUBNET_NET" -d "$GATEWAY" -p "$pt" -m "$pt" --dport 53 -j ACCEPT || die 1265 | done 1266 | done 1267 | } 1268 | 1269 | 1270 | start_catch_dns() { 1271 | local GATEWAY 1272 | local PROTs 1273 | local iv pt 1274 | 1275 | echo 1276 | echo "iptables: redirect DNS queries to this host" 1277 | 1278 | for iv in "${IP_VERs[@]}"; do 1279 | [[ "$iv" -eq "4" ]] && GATEWAY="$GATEWAY4" 1280 | [[ "$iv" -eq "6" ]] && GATEWAY="$GATEWAY6" 1281 | 1282 | PROTs=("tcp" "udp") 1283 | for pt in "${PROTs[@]}"; do 1284 | iptb "$iv" v nat I PREROUTING -i "$SUBNET_IFACE" ! -d "$GATEWAY" -p "$pt" -m "$pt" --dport 53 -j REDIRECT --to-ports 53 || die 1285 | done 1286 | done 1287 | } 1288 | 1289 | 1290 | allow_dhcp() { 1291 | echo 1292 | echo "iptables: allow dhcp" 1293 | 1294 | iptb 4 v filter I INPUT -i "${SUBNET_IFACE}" -p udp -m udp --dport 67 -j ACCEPT || die 1295 | iptb 6 v filter I INPUT -i "${SUBNET_IFACE}" -p udp -m udp --dport 547 -j ACCEPT || die 1296 | } 1297 | 1298 | # TODO: use 'DNAT' instead of '--to-ports' to support other IP 1299 | start_redsocks() { 1300 | local SUBNET_NET 1301 | local arr_nets_to_ignore 1302 | local s iv 1303 | 1304 | echo 1305 | echo "iptables: transparent proxy non-LAN TCP and UDP(not tested) traffic to port ${TP_PORT}" 1306 | 1307 | for iv in "${IP_VERs[@]}"; do 1308 | [[ "$iv" -eq "4" && ! $NO4 -eq 0 ]] && continue 1309 | 1310 | [[ "$iv" -eq "4" ]] && SUBNET_NET="$SUBNET_NET4" 1311 | [[ "$iv" -eq "6" ]] && SUBNET_NET="$SUBNET_NET6" 1312 | 1313 | 1314 | iptb "$iv" n nat N lrt${$}${SUBNET_IFACE}-TP || die 1315 | 1316 | if [[ "$iv" -eq "4" ]]; then 1317 | arr_nets_to_ignore=("0.0.0.0/8" "10.0.0.0/8" "100.64.0.0/10" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12" "192.168.0.0/16" "224.0.0.0/4" "255.255.255.255") 1318 | elif [[ "$iv" -eq "6" ]];then 1319 | arr_nets_to_ignore=("fc00::/7" "fe80::/10" "ff00::/8" "::1" "::") 1320 | fi 1321 | 1322 | for s in "${arr_nets_to_ignore[@]}"; do 1323 | iptb "$iv" n nat A lrt${$}${SUBNET_IFACE}-TP -d "$s" -j RETURN || die 1324 | done 1325 | 1326 | iptb "$iv" v nat A lrt${$}${SUBNET_IFACE}-TP -p tcp -j REDIRECT --to-ports ${TP_PORT} || die 1327 | iptb "$iv" v nat A lrt${$}${SUBNET_IFACE}-TP -p udp -j REDIRECT --to-ports ${TP_PORT} || die 1328 | 1329 | iptb "$iv" v nat I PREROUTING -i "$SUBNET_IFACE" -s "$SUBNET_NET" -j lrt${$}${SUBNET_IFACE}-TP || die 1330 | 1331 | 1332 | iptb "$iv" v filter I INPUT -i "$SUBNET_IFACE" -s "$SUBNET_NET" -p tcp -m tcp --dport "${TP_PORT}" -j ACCEPT || die 1333 | iptb "$iv" v filter I INPUT -i "$SUBNET_IFACE" -s "$SUBNET_NET" -p udp -m udp --dport "${TP_PORT}" -j ACCEPT || die 1334 | done 1335 | } 1336 | 1337 | #--------------------------------------- 1338 | backup_ipv6_bits() { 1339 | mkdir "$CONFDIR/sys_6_conf_iface" || die "Failed making dir to save interface IPv6 status" 1340 | cp "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/disable_ipv6" \ 1341 | "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/accept_ra" \ 1342 | "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/use_tempaddr" \ 1343 | "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/addr_gen_mode" \ 1344 | "$CONFDIR/sys_6_conf_iface/" || die "Failed backing up interface ipv6 bits" 1345 | 1346 | if [[ "$SHARE_METHOD" == 'redsocks' ]] ; then 1347 | cp "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/forwarding" \ 1348 | "$CONFDIR/sys_6_conf_iface/" || die "Failed backking up interface ipv6 bits" 1349 | fi 1350 | } 1351 | set_ipv6_bits() { 1352 | if [[ $IPV6 -eq 1 ]]; then 1353 | echo 0 > "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/disable_ipv6" 1354 | echo 0 > "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/accept_ra" 1355 | echo 0 > "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/use_tempaddr" 1356 | echo 0 > "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/addr_gen_mode" 1357 | else 1358 | echo 1 > "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/disable_ipv6" 1359 | fi 1360 | } 1361 | restore_ipv6_bits() { 1362 | if [[ -d "$CONFDIR/sys_6_conf_iface" ]]; then 1363 | cp -f "$CONFDIR/sys_6_conf_iface/*" "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/" 1364 | fi 1365 | } 1366 | 1367 | set_interface_mac() { 1368 | local INTERFACE 1369 | local MAC 1370 | 1371 | INTERFACE=$1 1372 | MAC=$2 1373 | 1374 | ip link set dev "${INTERFACE}" address "${MAC}" 1375 | } 1376 | 1377 | backup_interface_status() { 1378 | # virtual wifi interface will be destroyed, so no need to save status 1379 | 1380 | # backup interface up or down status 1381 | (ip link show "${SUBNET_IFACE}" |grep -q "state UP") && SUBNET_IFACE_ORIGINAL_UP_STATUS=1 1382 | 1383 | # save interface old mac 1384 | #if [[ -n "$NEW_MACADDR" ]]; then 1385 | OLD_MACADDR=$(get_interface_mac "$SUBNET_IFACE") 1386 | #echo "Saved ${SUBNET_IFACE} old MAC address ${OLD_MACADDR} into RAM" 1387 | #fi 1388 | 1389 | backup_ipv6_bits 1390 | 1391 | # TODO : ? backup ip and others??? 1392 | 1393 | # nm managing status is saved when nm_set_unmanaged() 1394 | } 1395 | restore_interface_status() { 1396 | # virtual wifi interface will be destroyed, so no need to restore status 1397 | # don't use [[ $VWIFI_IFACE ]] to judge, if creating virtual wifi failed, VWIFI_IFACE is empty 1398 | [[ "$WIFI_IFACE" && "$NO_VIRT" -eq 0 ]] && return 1399 | 1400 | restore_ipv6_bits 1401 | 1402 | if [[ -n "$OLD_MACADDR" && "$(get_interface_mac "$SUBNET_IFACE")" != "$OLD_MACADDR" ]] ; then 1403 | echo "Restoring ${SUBNET_IFACE} to old MAC address ${OLD_MACADDR} ..." 1404 | set_interface_mac "${SUBNET_IFACE}" "${OLD_MACADDR}" || echo "Failed restoring ${SUBNET_IFACE} to old MAC address ${OLD_MACADDR}" >&2 1405 | fi 1406 | 1407 | nm_restore_manage 1408 | 1409 | [[ $SUBNET_IFACE_ORIGINAL_UP_STATUS -eq 1 ]] && ip link set up dev "${SUBNET_IFACE}" && echo "Restore ${SUBNET_IFACE} to link up" 1410 | } 1411 | #--------------------------------------- 1412 | 1413 | kill_processes() { # for this instance 1414 | #echo "Killing processes" 1415 | local x pid 1416 | for x in $CONFDIR/*.pid; do 1417 | # even if the $CONFDIR is empty, the for loop will assign 1418 | # a value in $x. so we need to check if the value is a file 1419 | if [[ -f $x ]] && sleep 0.3 && [[ -f $x ]]; then 1420 | pid=$(cat "$x") 1421 | pn=$( ps -p "$pid" -o comm= ) 1422 | #echo "Killing $pid $pn ... " 1423 | pkill -P "$pid" 1424 | kill "$pid" 2>/dev/null && ( echo "Killed $(basename "$x") $pid $pn" && rm "$x" ) || echo "Failed to kill $(basename "$x") $pid $pn, it may have exited" 1425 | fi 1426 | done 1427 | } 1428 | 1429 | _cleanup() { 1430 | local x 1431 | 1432 | ip addr flush "${SUBNET_IFACE}" 1433 | 1434 | [[ ! "$KEEP_CONFDIR" -eq 1 ]] && rm -rf "$CONFDIR" 1435 | 1436 | ip link set down dev "${SUBNET_IFACE}" 1437 | 1438 | firewalld_restoreoldzone 1439 | 1440 | if [[ -n "$VWIFI_IFACE" ]]; then # the subnet interface (virtual wifi interface) will be removed 1441 | iw dev "${VWIFI_IFACE}" del 1442 | dealloc_vface_name "$VWIFI_IFACE" 1443 | fi 1444 | 1445 | restore_interface_status 1446 | 1447 | if ! has_running_instance; then 1448 | echo "Exiting: This is the only running instance" 1449 | # kill common processes 1450 | for x in $COMMON_CONFDIR/*.pid; do 1451 | [[ -f $x ]] && kill -9 $(cat "$x") && rm "$x" 1452 | done 1453 | 1454 | rm -d "$COMMON_CONFDIR/vfaces" 1455 | rm -d "$COMMON_CONFDIR" 1456 | rm -d "$TMPDIR" 1457 | else 1458 | echo "Exiting: This is NOT the only running instance" 1459 | fi 1460 | } 1461 | 1462 | clean_iptables() { 1463 | [[ -f $CONFDIR/undo_iptables.sh ]] && bash $CONFDIR/undo_iptables.sh 1464 | 1465 | [[ -f $CONFDIR/undo_iptables_2.sh ]] && bash $CONFDIR/undo_iptables_2.sh 1466 | } 1467 | 1468 | cleanup() { 1469 | trap "" SIGINT SIGUSR1 SIGUSR2 EXIT SIGTERM 1470 | touch "$CONFDIR/exit_$(date +"%Y-%m-%d_%H:%M:%S.%6N")" 1471 | echo 1472 | echo 1473 | echo "Doing cleanup.. " 1474 | kill_processes 1475 | echo "Undoing iptables changes .." 1476 | clean_iptables > /dev/null 1477 | _cleanup 2> /dev/null 1478 | 1479 | #pgid=$(ps opgid= $$ |awk '{print $1}' ) 1480 | #echo "Killing PGID $pgid ..." 1481 | #kill -15 -$pgid 1482 | #sleep 1 1483 | echo "Cleaning up done" 1484 | #kill -9 -$pgid 1485 | } 1486 | 1487 | # NOTE function die() is designed NOT to be used before init_trap() executed 1488 | die() { # SIGUSR2 1489 | echo "Error occured" 1490 | [[ -n "$1" ]] && echo -e "\nERROR: $1\n" >&2 1491 | # send die signal to the main process 1492 | [[ $BASHPID -ne $$ ]] && kill -USR2 $$ || cleanup 1493 | exit 1 1494 | } 1495 | 1496 | clean_exit() { # SIGUSR1 1497 | # send clean_exit signal to the main process 1498 | [[ $BASHPID -ne $$ ]] && kill -USR1 $$ || cleanup 1499 | exit 0 1500 | } 1501 | 1502 | init_trap(){ 1503 | trap "cleanup" EXIT 1504 | trap "clean_exit" SIGINT SIGUSR1 SIGTERM 1505 | trap "die" SIGUSR2 1506 | } 1507 | init_conf_dirs() { 1508 | mkdir -p "$TMPDIR" || die "Couldn't make linux-router's temporary dir" 1509 | chmod 755 "$TMPDIR" 2>/dev/null 1510 | cd "$TMPDIR" || die "Couldn't change directory to linux-router's temporary path" 1511 | 1512 | CONFDIR="$(mktemp -d $TMPDIR/lnxrouter.${TARGET_IFACE}.conf.XXXXXX)" || die "Instance couldn't make config dir" # config dir for one instance 1513 | echo "Config dir: $CONFDIR" 1514 | chmod 755 "$CONFDIR" || die "chmod config dir failed" 1515 | echo $$ > "$CONFDIR/pid" 1516 | 1517 | touch "$CONFDIR/begin_$(date +"%Y-%m-%d_%H:%M:%S.%6N")" 1518 | 1519 | COMMON_CONFDIR="$TMPDIR/lnxrouter_common.conf" # config dir for all instances 1520 | mkdir -p "$COMMON_CONFDIR" || die "Failed creating common config dir" 1521 | } 1522 | 1523 | #== functions to deal with running instances 1524 | 1525 | list_running_conf() { 1526 | local x 1527 | for x in $TMPDIR/lnxrouter.*; do 1528 | if [[ -f $x/pid && -f $x/subn_iface && -d /proc/$(cat $x/pid) ]]; then 1529 | echo "$x" 1530 | fi 1531 | done 1532 | } 1533 | 1534 | list_running() { 1535 | local IFACE subn_iface x 1536 | for x in $(list_running_conf); do 1537 | IFACE=${x#*.} 1538 | IFACE=${IFACE%%.*} 1539 | subn_iface=$(cat $x/subn_iface) 1540 | 1541 | if [[ "$IFACE" == "$subn_iface" ]]; then 1542 | echo $(cat $x/pid) $IFACE 1543 | else 1544 | echo $(cat $x/pid) $IFACE '('$(cat $x/subn_iface)')' 1545 | fi 1546 | done 1547 | } 1548 | 1549 | get_subn_iface_from_pid() { 1550 | list_running | awk '{print $1 " " $NF}' | tr -d '\(\)' | grep -E "^${1} " | cut -d' ' -f2 1551 | } 1552 | 1553 | get_pid_from_subn_iface() { 1554 | list_running | awk '{print $1 " " $NF}' | tr -d '\(\)' | grep -E " ${1}$" | cut -d' ' -f1 1555 | } 1556 | 1557 | get_confdir_from_pid() { 1558 | local IFACE x 1559 | for x in $(list_running_conf); do 1560 | if [[ $(cat $x/pid) == "$1" ]]; then 1561 | echo "$x" 1562 | break 1563 | fi 1564 | done 1565 | } 1566 | 1567 | #====================================================== 1568 | 1569 | print_clients_from_leases() { # MAC|IP|HOST|lease 1570 | local LEASE_FILE="$1" 1571 | local FILEC 1572 | local line 1573 | local LEASEstr LEASEstamp 1574 | 1575 | FILEC="$(cat "$LEASE_FILE" | grep -v -E "^duid\b" | sed -r '/^\s*$/d' )" 1576 | 1577 | # TODO: duid is somewhat related to ipv6. I don't know about it. Not sure excluding it miss some info or not 1578 | echo "$FILEC" | while read -r line 1579 | do 1580 | #echo aa$line 1581 | LEASEstamp="$(echo "$line" | awk '{print $1}')" 1582 | MAC="$(echo "$line" | awk '{print $2}')" 1583 | IP="$(echo "$line" | awk '{print $3}' | sed 's/\[//g' | sed 's/\]//g')" 1584 | HOST="$(echo "$line" | awk '{print $4}' | sed 's/*/?/g' | sed 's/|/_/g' | sed 's/ /_/g' )" 1585 | 1586 | if [[ -n "$MAC" ]]; then 1587 | LEASEstr="$(date -d @${LEASEstamp} +%m-%d_%X)" 1588 | 1589 | echo "$MAC|$IP|$HOST|lease_$LEASEstr" 1590 | fi 1591 | done 1592 | 1593 | } 1594 | print_interface_neighbors_via_iproute() { # MAC|IP|_|STATUS 1595 | local IFACE=$1 1596 | 1597 | local line 1598 | 1599 | ip n | grep -E "\bdev $IFACE\b" | sed 's/ /|/g' | while read -r line 1600 | do 1601 | local MAC IP STATUS 1602 | 1603 | IP="$(echo "$line" | awk -F'|' '{print $1}')" 1604 | 1605 | if [[ "$(echo "$line" | awk -F'|' '{print $4}')" == "lladdr" ]]; then # has mac 1606 | # if has mac, $4="lladdr" and $5=macaddress and $6+=status 1607 | MAC="$(echo "$line" | awk -F'|' '{print $5}')" 1608 | STATUS="$(echo "$line" | awk -F'|' '$1="";$2="";$3="";$4="";$5="";{print}' | awk '{$1=$1;print}'| sed 's/ /,/g')" 1609 | else # no mac 1610 | # if no mac, $4="" and $5+=status 1611 | MAC="?" 1612 | STATUS="$(echo "$line" | awk -F'|' '$1="";$2="";$3="";$4="";{print}' | awk '{$1=$1;print}' | sed 's/ /,/g')" 1613 | fi 1614 | if [[ -n "$IP" && ( "$MAC" != "?" || "$STATUS" != "FAILED" ) ]]; then 1615 | echo "$MAC|$IP|?|$STATUS" 1616 | fi 1617 | done 1618 | } 1619 | print_interface_neighbors_via_iw() { # MAC|_|_|signal 1620 | local IFACE=$1 1621 | local MAC SIGNAL 1622 | iw dev "$IFACE" station dump | awk '($1 ~ /Station$/) {print $2}' | while read -r MAC 1623 | do 1624 | if [[ -n "$MAC" ]]; then 1625 | SIGNAL="$(iw dev "$IFACE" station get "$MAC" | grep "signal:" | awk '{print $2}')" 1626 | echo "${MAC}|?|?|${SIGNAL}_dBm" 1627 | fi 1628 | done 1629 | } 1630 | 1631 | list_clients() { # passive mode. (use 'arp-scan' or 'netdiscover' if want active mode) 1632 | local IFACE pid 1633 | local CONFDIR 1634 | 1635 | local output="" 1636 | # If number (PID) is given, get the associated wifi iface 1637 | if [[ "$1" =~ ^[1-9][0-9]*$ ]]; then 1638 | pid="$1" 1639 | IFACE=$(get_subn_iface_from_pid "$pid") 1640 | if [[ -z "$IFACE" ]] ; then 1641 | echo "'$pid' is not the pid of a running $PROGNAME instance." >&2 1642 | exit 1 1643 | fi 1644 | else # non-number given 1645 | IFACE="$1" 1646 | if ( ! is_interface "$IFACE" ) ; then 1647 | echo "'$IFACE' is not an interface or PID" >&2 1648 | exit 1 1649 | fi 1650 | pid=$(get_pid_from_subn_iface "$IFACE") 1651 | if [[ -n "$pid" ]] ; then # if this interface is hosted by us 1652 | CONFDIR=$(get_confdir_from_pid "$pid") 1653 | output="$(print_clients_from_leases "$CONFDIR/dnsmasq.leases" )" 1654 | else # this interface NOT hosted by us 1655 | echo "Tip: '$IFACE' is not an interface hosted by $PROGNAME" >&2 1656 | fi 1657 | fi 1658 | output="$(echo "$output" ; print_interface_neighbors_via_iw "$IFACE") " 1659 | output="$(echo "$output" ; print_interface_neighbors_via_iproute "$IFACE")" 1660 | 1661 | output="$(echo "$output" | sort -k 1 -k 2 -t '|' | uniq | sed -r '/^\s*$/d')" 1662 | 1663 | echo "$IFACE ($(get_interface_mac "$IFACE")) neighbors:" 1664 | 1665 | local fmt="%-19s%-41s%-20s%s" # string length: MAC 17, ipv4 15, ipv6 39, hostname ? 1666 | printf "$fmt\n" "MAC" "IP" "HOSTNAME" "INFO" 1667 | 1668 | local line 1669 | echo "$output"| while read -r line 1670 | do 1671 | if [[ -n "$line" ]]; then 1672 | echo "$line" | awk -F'|' "{printf \"$fmt\n\",\$1,\$2,\$3,\$4}" 1673 | fi 1674 | done 1675 | # TODO : merge same mac and same ip line 1676 | } 1677 | 1678 | has_running_instance() { 1679 | local PID x 1680 | 1681 | for x in $TMPDIR/lnxrouter.*; do 1682 | if [[ -f $x/pid ]]; then 1683 | PID=$(cat $x/pid) 1684 | if [[ -d /proc/$PID ]]; then 1685 | return 0 1686 | fi 1687 | fi 1688 | done 1689 | 1690 | return 1 1691 | } 1692 | 1693 | is_running_pid() { 1694 | list_running | grep -E "^${1} " > /dev/null 2>&1 1695 | } 1696 | 1697 | send_stop() { 1698 | local x 1699 | 1700 | # send stop signal to specific pid 1701 | if is_running_pid "$1"; then 1702 | kill -USR1 "$1" 1703 | return 1704 | fi 1705 | 1706 | # send stop signal to specific interface 1707 | for x in $(list_running | grep -E " \(?${1}( |\)?\$)" | cut -f1 -d' '); do 1708 | kill -USR1 "$x" 1709 | done 1710 | } 1711 | 1712 | 1713 | ## ======================================================== 1714 | ## ======================================================== 1715 | # decide linux-router's global temporary path for all instances 1716 | # this is different and should be before config-saving dir. The latter is for one instance 1717 | decide_tmpdir(){ 1718 | local TMPD 1719 | if [[ -d /dev/shm ]]; then 1720 | TMPD=/dev/shm 1721 | elif [[ -d /run/shm ]]; then 1722 | TMPD=/run/shm 1723 | else 1724 | TMPD=/tmp 1725 | fi 1726 | #TMPDIR=$TMPD/lnxrouter_tmp 1727 | echo "$TMPD/lnxrouter_tmp" 1728 | } 1729 | 1730 | #====== 1731 | 1732 | check_other_functions(){ 1733 | if [[ $LIST_RUNNING -eq 1 ]]; then 1734 | echo -e "List of running $PROGNAME instances:\n" 1735 | list_running 1736 | exit 0 1737 | fi 1738 | 1739 | if [[ -n "$LIST_CLIENTS_ID" ]]; then 1740 | list_clients "$LIST_CLIENTS_ID" 1741 | exit 0 1742 | fi 1743 | 1744 | ##### root test ##### NOTE above don't require root ########## 1745 | if [[ $(id -u) -ne 0 ]]; then 1746 | echo "ERROR: Need root to continue" >&2 1747 | exit 1 1748 | fi 1749 | ###### NOTE below require root ########## 1750 | 1751 | if [[ -n "$STOP_ID" ]]; then 1752 | echo "Trying to kill $PROGNAME instance associated with $STOP_ID..." 1753 | send_stop "$STOP_ID" 1754 | exit 0 1755 | fi 1756 | } 1757 | 1758 | 1759 | daemonizing_check(){ 1760 | if [[ $DAEMONIZE -eq 1 && $RUNNING_AS_DAEMON -eq 0 ]]; then 1761 | echo "Running as Daemon..." 1762 | # run a detached lnxrouter 1763 | RUNNING_AS_DAEMON=1 setsid "$0" "${ARGS[@]}" & 1764 | exit 0 1765 | fi 1766 | } 1767 | 1768 | #============================ 1769 | check_wifi_settings() { 1770 | PHY="$(get_interface_phy_device "$WIFI_IFACE")" 1771 | if [[ -z "$PHY" ]]; then 1772 | echo "ERROR: Can't get phy of wifi interface '$WIFI_IFACE' (Did you spell the interface name right?)" >&2 1773 | exit 1 1774 | fi 1775 | 1776 | if ! ( which iw > /dev/null 2>&1 && iw dev "$WIFI_IFACE" info > /dev/null 2>&1 ); then 1777 | echo "WARN: Can't use 'iw' to operate interfce '$WIFI_IFACE', trying 'iwconfig' (not as good as 'iw') ..." >&2 1778 | USE_IWCONFIG=1 1779 | fi 1780 | 1781 | if [[ $USE_IWCONFIG -eq 1 ]]; then 1782 | if ! (which iwconfig > /dev/null 2>&1 && iwconfig "$WIFI_IFACE" > /dev/null 2>&1); then 1783 | echo "ERROR: Can't use 'iwconfig' to operate interfce '$WIFI_IFACE'" >&2 1784 | exit 1 1785 | fi 1786 | fi 1787 | 1788 | if [[ $FREQ_BAND != 2.4 && $FREQ_BAND != 5 ]]; then 1789 | echo "ERROR: Invalid frequency band" >&2 1790 | exit 1 1791 | fi 1792 | 1793 | if [[ $FREQ_BAND != 5 && $CHANNEL -gt 14 ]]; then 1794 | echo "Channel number is greater than 14, assuming 5GHz frequency band" 1795 | FREQ_BAND=5 1796 | fi 1797 | 1798 | if ! can_be_ap "${WIFI_IFACE}"; then 1799 | echo "ERROR: Your adapter does not support AP (master) mode" >&2 1800 | exit 1 1801 | fi 1802 | 1803 | if ! can_be_sta_and_ap "${WIFI_IFACE}"; then 1804 | if is_interface_wifi_connected "${WIFI_IFACE}"; then 1805 | echo "ERROR: Your adapter can not be a station (i.e. be connected) and an AP at the same time" >&2 1806 | exit 1 1807 | elif [[ $NO_VIRT -eq 0 ]]; then 1808 | echo "WARN: Your adapter does not fully support AP virtual interface, enabling --no-virt" >&2 1809 | NO_VIRT=1 1810 | fi 1811 | fi 1812 | 1813 | HOSTAPD=$(which hostapd) 1814 | 1815 | if [[ $(get_adapter_kernel_module "${WIFI_IFACE}") =~ ^(8192[cd][ue]|8723a[sue])$ ]]; then 1816 | if ! strings "$HOSTAPD" | grep -m1 rtl871xdrv > /dev/null 2>&1; then 1817 | echo "ERROR: You need to patch your hostapd with rtl871xdrv patches." >&2 1818 | exit 1 1819 | fi 1820 | 1821 | if [[ $DRIVER != "rtl871xdrv" ]]; then 1822 | echo "WARN: Your adapter needs rtl871xdrv, enabling --driver=rtl871xdrv" >&2 1823 | DRIVER=rtl871xdrv 1824 | fi 1825 | fi 1826 | 1827 | if [[ ${#SSID} -lt 1 || ${#SSID} -gt 32 ]]; then 1828 | echo "ERROR: Invalid SSID length ${#SSID} (expected 1..32)" >&2 1829 | exit 1 1830 | fi 1831 | 1832 | if [[ $USE_PSK -eq 0 ]]; then 1833 | if [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -lt 8 ]] || [[ ${#PASSPHRASE} -gt 63 ]]; then 1834 | echo "ERROR: Invalid passphrase length ${#PASSPHRASE} (expected 8..63)" >&2 1835 | exit 1 1836 | fi 1837 | elif [[ ${#PASSPHRASE} -gt 0 && ${#PASSPHRASE} -ne 64 ]]; then 1838 | echo "ERROR: Invalid pre-shared-key length ${#PASSPHRASE} (expected 64)" >&2 1839 | exit 1 1840 | fi 1841 | 1842 | if [[ $(get_adapter_kernel_module "${WIFI_IFACE}") =~ ^rtl[0-9].*$ ]]; then 1843 | if [[ $WPA_VERSION == '1' || $WPA_VERSION == '1+2' ]]; then 1844 | echo "WARN: Realtek drivers usually have problems with WPA1, WPA2 is recommended" >&2 1845 | fi 1846 | echo "WARN: If AP doesn't work, read https://github.com/oblique/create_ap/blob/master/howto/realtek.md" >&2 1847 | fi 1848 | 1849 | if [[ -z $VIRT_NAME ]]; then 1850 | if [[ ${#WIFI_IFACE} -gt 13 ]]; then 1851 | echo "WARN: $WIFI_IFACE has ${#WIFI_IFACE} characters which might be too long. If AP doesn't work, see --virt-name and https://github.com/garywill/linux-router/issues/44" >&2 1852 | fi 1853 | elif [[ ${#VIRT_NAME} -gt 15 ]]; then 1854 | echo "WARN: option --virt-name $VIRT_NAME has ${#VIRT_NAME} characters which might be too long, consider making it shorter in case of errors" >&2 1855 | fi 1856 | 1857 | if [[ ! -z $VIRT_NAME ]] && is_vface_name_allocated "$VIRT_NAME"; then 1858 | echo "WARN: interface $VIRT_NAME aleady exists, this will cause an error" 1859 | fi 1860 | } 1861 | 1862 | check_if_new_mac_valid() { 1863 | if ! is_unicast_macaddr "$NEW_MACADDR"; then 1864 | echo "ERROR: The first byte of MAC address (${NEW_MACADDR}) must be even" >&2 1865 | exit 1 1866 | fi 1867 | 1868 | if [[ $(get_all_mac_in_system | grep -c "${NEW_MACADDR}") -ne 0 ]]; then 1869 | echo "WARN: MAC address '${NEW_MACADDR}' already exists" >&2 1870 | fi 1871 | } 1872 | 1873 | decide_target_interface() { 1874 | # TARGET_IFACE is a existing physical interface 1875 | if [[ "$CONN_IFACE" ]]; then 1876 | echo "$CONN_IFACE" 1877 | elif [[ "$WIFI_IFACE" ]]; then 1878 | echo "$WIFI_IFACE" 1879 | else 1880 | echo "No target interface specified" >&2 1881 | return 1 1882 | fi 1883 | } 1884 | 1885 | decide_ip_addresses() { 1886 | if [[ ! -n $GATEWAY4 ]]; then 1887 | GATEWAY4="$(generate_random_ip4)" 1888 | echo "Use random LAN IPv4 address $GATEWAY4" 1889 | elif [[ ! "$GATEWAY4" =~ "." ]]; then 1890 | GATEWAY4="192.168.${GATEWAY4}.1" 1891 | fi 1892 | 1893 | if [[ $IPV6 -eq 1 && ! -n $PREFIX6 ]]; then 1894 | PREFIX6="$(generate_random_lan_ip6_prefix)" 1895 | echo "Use random LAN IPv6 address ${PREFIX6}${IID6}" 1896 | elif [[ ! "$PREFIX6" =~ ":" ]]; then 1897 | PREFIX6="fd00:0:0:${PREFIX6}::" 1898 | fi 1899 | if [[ $IPV6 -eq 1 ]]; then 1900 | GATEWAY6="${PREFIX6}${IID6}" 1901 | fi 1902 | 1903 | SUBNET_NET4="${GATEWAY4%.*}.0/24" 1904 | [[ $IPV6 -eq 1 ]] && SUBNET_NET6="${PREFIX6}/64" 1905 | 1906 | } 1907 | 1908 | prepare_wifi_interface() { 1909 | if [[ $USE_IWCONFIG -eq 0 ]]; then 1910 | iw dev "${WIFI_IFACE}" set power_save off 1911 | fi 1912 | 1913 | if [[ $NO_VIRT -eq 0 ]]; then 1914 | ## Will generate virtual wifi interface 1915 | 1916 | # TODO move this to check_wifi_settings() ? 1917 | if is_interface_wifi_connected "${WIFI_IFACE}"; then 1918 | WIFI_IFACE_FREQ=$(iw dev "${WIFI_IFACE}" link | grep -i freq | awk '{print $2}' | sed 's/\.00*$//g') # NOTE we assume integer currently, which can be right, or wrong in the future 1919 | WIFI_IFACE_CHANNEL=$(ieee80211_frequency_to_channel "${WIFI_IFACE_FREQ}") 1920 | 1921 | echo "${WIFI_IFACE} already working in channel ${WIFI_IFACE_CHANNEL} (${WIFI_IFACE_FREQ} MHz)" 1922 | 1923 | if [[ $CHANNEL == default ]]; then 1924 | echo "Use wifi adapter current channel $WIFI_IFACE_CHANNEL as target channel" 1925 | CHANNEL=$WIFI_IFACE_CHANNEL 1926 | fi 1927 | 1928 | if [[ $WIFI_IFACE_CHANNEL -ne $CHANNEL ]]; then 1929 | echo "WARN: Wifi adapter already working in channel ${WIFI_IFACE_CHANNEL}, which is different than target channel $CHANNEL" >&2 1930 | fi 1931 | fi 1932 | 1933 | echo "Creating a virtual WiFi interface... " 1934 | VWIFI_IFACE=$(alloc_new_vface_name) 1935 | if iw dev "${WIFI_IFACE}" interface add "${VWIFI_IFACE}" type __ap; then 1936 | # Successfully created virtual wifi interface 1937 | # if NM running, it will give the new virtual interface a random MAC. MAC will go back after setting NM unmanaged 1938 | sleep 2 1939 | echo "${VWIFI_IFACE} created" 1940 | else 1941 | VWIFI_IFACE= 1942 | if [[ ! -z ${VIRT_NAME} ]] && [[ ${#VIRT_NAME} -gt 15 ]]; then 1943 | die "Failed creating virtual WiFi interface. This is likely because you have set a long name for your virtual interface using --virt-name, try making it shorter'" 1944 | elif [[ -z ${VIRT_NAME} ]] && [[ ${#WIFI_IFACE} -gt 13 ]]; then 1945 | die "Failed creating virtual WiFi interface. This is likely because your interface name is too long. Try using '--virt-name '" 1946 | else 1947 | die "Failed creating virtual WiFi interface. Maybe your WiFi adapter does not fully support virtual interfaces. Try again with '--no-virt'" 1948 | fi 1949 | fi 1950 | 1951 | AP_IFACE=${VWIFI_IFACE} 1952 | else # no virtual wifi interface, use wifi device interface itself 1953 | AP_IFACE=${WIFI_IFACE} 1954 | fi 1955 | 1956 | if [[ $CHANNEL == default ]]; then 1957 | echo "Channel not specified, use default" 1958 | if [[ $FREQ_BAND == 2.4 ]]; then 1959 | CHANNEL=1 1960 | else 1961 | CHANNEL=36 1962 | fi 1963 | fi 1964 | 1965 | echo "Freq band: $FREQ_BAND GHz Channel: $CHANNEL" 1966 | } 1967 | 1968 | decide_subnet_interface() { 1969 | if [[ $WIFI_IFACE ]]; then 1970 | echo "${AP_IFACE}" 1971 | else 1972 | echo "${TARGET_IFACE}" 1973 | fi 1974 | } 1975 | 1976 | dealwith_mac() { 1977 | local VMAC 1978 | 1979 | if [[ -n "$NEW_MACADDR" ]] ; then # user choose to set subnet mac 1980 | 1981 | echo "Setting ${SUBNET_IFACE} new MAC address ${NEW_MACADDR} ..." 1982 | set_interface_mac "${SUBNET_IFACE}" "${NEW_MACADDR}" || die "Failed setting new MAC address" 1983 | 1984 | elif [[ $VWIFI_IFACE ]]; then # user didn't choose to set mac, but using virtual wifi interface 1985 | 1986 | VMAC=$(get_new_macaddr_according_to_existing "${WIFI_IFACE}") 1987 | if [[ "$VMAC" ]]; then 1988 | echo "Assigning MAC address $VMAC to virtual interface $VWIFI_IFACE according to $WIFI_IFACE ..." 1989 | set_interface_mac "$VWIFI_IFACE" "$VMAC" 1990 | fi 1991 | fi 1992 | } 1993 | 1994 | write_hostapd_conf() { 1995 | cat <<- EOF > "$CONFDIR/hostapd.conf" 1996 | beacon_int=100 1997 | ssid=${SSID} 1998 | interface=${AP_IFACE} 1999 | driver=${DRIVER} 2000 | channel=${CHANNEL} 2001 | ctrl_interface=$CONFDIR/hostapd_ctrl 2002 | ctrl_interface_group=0 2003 | ignore_broadcast_ssid=$HIDDEN 2004 | ap_isolate=$ISOLATE_CLIENTS 2005 | EOF 2006 | 2007 | if [[ -n "$COUNTRY" ]]; then 2008 | cat <<- EOF >> "$CONFDIR/hostapd.conf" 2009 | country_code=${COUNTRY} 2010 | ieee80211d=1 2011 | EOF 2012 | fi 2013 | 2014 | if [[ $FREQ_BAND == 2.4 ]]; then 2015 | echo "hw_mode=g" >> "$CONFDIR/hostapd.conf" 2016 | else 2017 | echo "hw_mode=a" >> "$CONFDIR/hostapd.conf" 2018 | fi 2019 | 2020 | if [[ $MAC_FILTER -eq 1 ]]; then 2021 | cat <<- EOF >> "$CONFDIR/hostapd.conf" 2022 | macaddr_acl=${MAC_FILTER} 2023 | accept_mac_file=${MAC_FILTER_ACCEPT} 2024 | EOF 2025 | fi 2026 | 2027 | if [[ -n "$PASSPHRASE" ]]; then 2028 | [[ "$WPA_VERSION" == "1+2" ]] && WPA_VERSION=3 2029 | if [[ $USE_PSK -eq 0 ]]; then 2030 | WPA_KEY_TYPE=passphrase 2031 | else 2032 | WPA_KEY_TYPE=psk 2033 | fi 2034 | cat <<- EOF >> "$CONFDIR/hostapd.conf" 2035 | wpa=${WPA_VERSION} 2036 | wpa_${WPA_KEY_TYPE}=${PASSPHRASE} 2037 | wpa_key_mgmt=WPA-PSK 2038 | wpa_pairwise=CCMP 2039 | rsn_pairwise=CCMP 2040 | EOF 2041 | else 2042 | echo "WARN: WiFi is not protected by password" >&2 2043 | fi 2044 | 2045 | if [[ $HOTSPOT20 -eq 1 ]]; then 2046 | echo "hs20=1" >> "$CONFDIR/hostapd.conf" 2047 | fi 2048 | 2049 | if [[ -n "$STATIMEOUT" ]]; then 2050 | echo "ap_max_inactivity=${STATIMEOUT}" >> "$CONFDIR/hostapd.conf" 2051 | fi 2052 | 2053 | if [[ $IEEE80211N -eq 1 ]]; then # wifi4 2054 | echo "ieee80211n=1" >> "$CONFDIR/hostapd.conf" 2055 | 2056 | if [[ -n "$HT_CAPAB" ]]; then 2057 | echo "ht_capab=${HT_CAPAB}" >> "$CONFDIR/hostapd.conf" 2058 | fi 2059 | 2060 | if [[ $REQUIREHT -eq 1 ]]; then 2061 | echo "require_ht=1" >> "$CONFDIR/hostapd.conf" 2062 | fi 2063 | fi 2064 | 2065 | if [[ $IEEE80211AC -eq 1 ]]; then # wifi5 2066 | echo "ieee80211ac=1" >> "$CONFDIR/hostapd.conf" 2067 | 2068 | if [[ -n "$VHT_CAPAB" ]]; then 2069 | echo "vht_capab=${VHT_CAPAB}" >> "$CONFDIR/hostapd.conf" 2070 | fi 2071 | 2072 | if [[ -n "$VHTCHANNELWIDTH" ]]; then 2073 | echo "vht_oper_chwidth=${VHTCHANNELWIDTH}" >> "$CONFDIR/hostapd.conf" 2074 | fi 2075 | 2076 | if [[ -n "$VHTSEG0CHINDEX" ]]; then 2077 | echo "vht_oper_centr_freq_seg0_idx=${VHTSEG0CHINDEX}" >> "$CONFDIR/hostapd.conf" 2078 | fi 2079 | 2080 | if [[ -n "$VHTSEG1CHINDEX" ]]; then 2081 | echo "vht_oper_centr_freq_seg1_idx=${VHTSEG1CHINDEX}" >> "$CONFDIR/hostapd.conf" 2082 | fi 2083 | 2084 | if [[ $REQUIREVHT -eq 1 ]]; then 2085 | echo "require_vht=1" >> "$CONFDIR/hostapd.conf" 2086 | fi 2087 | fi 2088 | 2089 | if [[ $IEEE80211AX -eq 1 ]]; then # wifi6 2090 | echo "ieee80211ax=1" >> "$CONFDIR/hostapd.conf" 2091 | 2092 | if [[ $REQUIREHE -eq 1 ]]; then 2093 | echo "require_he=1" >> "$CONFDIR/hostapd.conf" 2094 | fi 2095 | 2096 | if [[ $HESUBFE -eq 1 ]]; then 2097 | echo "he_su_beamformee=1" >> "$CONFDIR/hostapd.conf" 2098 | fi 2099 | 2100 | if [[ $HESUBFR -eq 1 ]]; then 2101 | echo "he_su_beamformer=1" >> "$CONFDIR/hostapd.conf" 2102 | fi 2103 | 2104 | if [[ $HEMUBFR -eq 1 ]]; then 2105 | echo "he_mu_beamformer=1" >> "$CONFDIR/hostapd.conf" 2106 | fi 2107 | 2108 | if [[ -n "$HECHANNELWIDTH" ]]; then 2109 | echo "he_oper_chwidth=${HECHANNELWIDTH}" >> "$CONFDIR/hostapd.conf" 2110 | fi 2111 | 2112 | if [[ -n "$HESEG0CHINDEX" ]]; then 2113 | echo "he_oper_centr_freq_seg0_idx=${HESEG0CHINDEX}" >> "$CONFDIR/hostapd.conf" 2114 | fi 2115 | 2116 | if [[ -n "$HESEG1CHINDEX" ]]; then 2117 | echo "he_oper_centr_freq_seg1_idx=${HESEG1CHINDEX}" >> "$CONFDIR/hostapd.conf" 2118 | fi 2119 | fi 2120 | 2121 | if [[ $P2PTWT -eq 1 ]]; then 2122 | echo "peer_to_peer_twt=1" >> "$CONFDIR/hostapd.conf" 2123 | fi 2124 | 2125 | if [[ $IEEE80211N -eq 1 ]] || [[ $IEEE80211AC -eq 1 ]] || [[ $IEEE80211AX -eq 1 ]]; then 2126 | echo "wmm_enabled=1" >> "$CONFDIR/hostapd.conf" 2127 | fi 2128 | 2129 | chmod 600 "$CONFDIR/hostapd.conf" 2130 | } 2131 | 2132 | write_dnsmasq_conf() { 2133 | local i 2134 | if grep "^nobody:" /etc/group >/dev/null 2>&1 ; then 2135 | NOBODY_GROUP="nobody" 2136 | else 2137 | NOBODY_GROUP="nogroup" 2138 | fi 2139 | 2140 | mkfifo "$CONFDIR/dnsmasq.log" || die "Failed creating pipe file for dnsmasq" 2141 | chown nobody "$CONFDIR/dnsmasq.log" || die "Failed changing dnsmasq log file owner" 2142 | cat "$CONFDIR/dnsmasq.log" & 2143 | 2144 | cat <<- EOF > "$CONFDIR/dnsmasq.conf" 2145 | user=nobody 2146 | group=$NOBODY_GROUP 2147 | bind-dynamic 2148 | listen-address=${GATEWAY4} 2149 | interface=$SUBNET_IFACE 2150 | except-interface=lo 2151 | no-dhcp-interface=lo 2152 | dhcp-range=${GATEWAY4%.*}.10,${GATEWAY4%.*}.250,255.255.255.0 2153 | dhcp-option-force=option:router,${GATEWAY4} 2154 | #log-dhcp 2155 | log-facility=$CONFDIR/dnsmasq.log 2156 | bogus-priv 2157 | domain-needed 2158 | EOF 2159 | # 'log-dhcp'(Extra logging for DHCP) shows too much logs. 2160 | # if use '-d', 'log-facility' should = /dev/null 2161 | if [[ $SHARE_METHOD == "none" ]]; then 2162 | echo "no-resolv" >> "$CONFDIR/dnsmasq.conf" 2163 | echo "no-poll" >> "$CONFDIR/dnsmasq.conf" 2164 | fi 2165 | if [[ "$DHCP_DNS" != "no" ]]; then 2166 | if [[ "$DHCP_DNS" == "gateway" ]]; then 2167 | dns_offer="$GATEWAY4" 2168 | else 2169 | dns_offer="$DHCP_DNS" 2170 | fi 2171 | echo "dhcp-option-force=option:dns-server,${dns_offer}" >> "$CONFDIR/dnsmasq.conf" 2172 | fi 2173 | 2174 | if [[ ! "$dnsmasq_NO_DNS" -eq 0 ]]; then 2175 | echo "port=0" >> "$CONFDIR/dnsmasq.conf" 2176 | fi 2177 | 2178 | [[ -n "$MTU" ]] && echo "dhcp-option-force=option:mtu,${MTU}" >> "$CONFDIR/dnsmasq.conf" 2179 | [[ $ETC_HOSTS -eq 0 ]] && echo no-hosts >> "$CONFDIR/dnsmasq.conf" 2180 | [[ -n "$ADDN_HOSTS" ]] && echo "addn-hosts=${ADDN_HOSTS}" >> "$CONFDIR/dnsmasq.conf" 2181 | if [[ "$THISHOSTNAME" ]]; then 2182 | [[ "$THISHOSTNAME" == "-" ]] && THISHOSTNAME="$(cat /etc/hostname)" 2183 | echo "interface-name=$THISHOSTNAME,$SUBNET_IFACE" >> "$CONFDIR/dnsmasq.conf" 2184 | fi 2185 | if [[ ! "$SHOW_DNS_QUERY" -eq 0 ]]; then 2186 | echo log-queries=extra >> "$CONFDIR/dnsmasq.conf" 2187 | fi 2188 | 2189 | if [[ $DNS ]]; then 2190 | DNS_count=$(echo "$DNS" | awk -F, '{print NF}') 2191 | for (( i=1;i<=DNS_count;i++ )); do 2192 | sep_ip_port "$(echo "$DNS" | cut -d, -f$i)" DNS_IP DNS_PORT 2193 | [[ "$DNS_PORT" ]] && DNS_PORT_D="#$DNS_PORT" 2194 | echo "server=${DNS_IP}${DNS_PORT_D}" >> "$CONFDIR/dnsmasq.conf" 2195 | done 2196 | 2197 | cat <<- EOF >> "$CONFDIR/dnsmasq.conf" 2198 | no-resolv 2199 | no-poll 2200 | EOF 2201 | fi 2202 | if [[ $DNS_NOCACHE -eq 1 ]]; then 2203 | echo "cache-size=0" >> "$CONFDIR/dnsmasq.conf" 2204 | echo "no-negcache" >> "$CONFDIR/dnsmasq.conf" 2205 | fi 2206 | if [[ $IPV6 -eq 1 ]];then 2207 | cat <<- EOF >> "$CONFDIR/dnsmasq.conf" 2208 | listen-address=${GATEWAY6} 2209 | enable-ra 2210 | #quiet-ra 2211 | dhcp-range=interface:${SUBNET_IFACE},::,::ffff:ffff:ffff:ffff,constructor:${SUBNET_IFACE},ra-stateless,64 2212 | EOF 2213 | if [[ "$DHCP_DNS6" != "no" ]]; then 2214 | if [[ "$DHCP_DNS6" == "gateway" ]]; then 2215 | dns_offer6="[$GATEWAY6]" 2216 | else 2217 | dns_offer6="$DHCP_DNS6" 2218 | fi 2219 | echo "dhcp-option=option6:dns-server,${dns_offer6}" >> "$CONFDIR/dnsmasq.conf" 2220 | fi 2221 | fi 2222 | } 2223 | 2224 | run_wifi_ap_processes() { 2225 | if [[ $NO_HAVEGED -eq 0 ]]; then 2226 | haveged_watchdog & 2227 | HAVEGED_WATCHDOG_PID=$! 2228 | echo "$HAVEGED_WATCHDOG_PID" > "$CONFDIR/haveged_watchdog.pid" 2229 | echo 2230 | echo "haveged_watchdog PID: $HAVEGED_WATCHDOG_PID" 2231 | fi 2232 | 2233 | # start access point 2234 | #echo "hostapd command-line interface: hostapd_cli -p $CONFDIR/hostapd_ctrl" 2235 | # start hostapd (use stdbuf when available for no delayed output in programs that redirect stdout) 2236 | STDBUF_PATH=$(which stdbuf) 2237 | if [ $? -eq 0 ]; then 2238 | STDBUF_PATH=$STDBUF_PATH" -oL" 2239 | fi 2240 | echo 2241 | echo "Starting hostapd" 2242 | 2243 | if COMPLAIN_CMD="$(command -v aa-complain || command -v complain)"; then 2244 | echo "Setting hostapd to AppArmor complain mode..." 2245 | "$COMPLAIN_CMD" hostapd 2246 | fi 2247 | 2248 | # hostapd '-P' works only when use '-B' (run in background) 2249 | $STDBUF_PATH hostapd $HOSTAPD_DEBUG_ARGS -P "$CONFDIR/hostapd.pid" "$CONFDIR/hostapd.conf" & 2250 | HOSTAPD_PID=$! 2251 | echo "$HOSTAPD_PID" > "$CONFDIR/hostapd.pid" 2252 | echo "hostapd PID: $HOSTAPD_PID" 2253 | #while [[ ! -f $CONFDIR/hostapd.pid ]]; do 2254 | # sleep 1 2255 | #done 2256 | #echo -n "hostapd PID: " ; cat $CONFDIR/hostapd.pid 2257 | pid_watchdog "$HOSTAPD_PID" 10 "hostapd failed. (tip: try '--hostapd-debug' to get some debug info)" & 2258 | sleep 3 2259 | } 2260 | 2261 | start_dnsmasq() { 2262 | echo 2263 | echo "Starting dnsmasq" 2264 | 2265 | if COMPLAIN_CMD="$(command -v aa-complain || command -v complain)"; then 2266 | echo "Setting dnsmasq to AppArmor complain mode..." 2267 | "$COMPLAIN_CMD" dnsmasq 2268 | fi 2269 | 2270 | # Using '-d'(no daemon) dnsmasq will not turn into 'nobody' 2271 | # '-x' works only when no '-d' 2272 | dnsmasq -k -C "$CONFDIR/dnsmasq.conf" -x "$CONFDIR/dnsmasq.pid" -l "$CONFDIR/dnsmasq.leases" & 2273 | #####DNSMASQ_PID=$! # only when with '-d' 2274 | ######echo "dnsmasq PID: $DNSMASQ_PID" # only when with '-d' 2275 | i=0; while [[ ! -f "$CONFDIR/dnsmasq.pid" ]]; do 2276 | sleep 1 2277 | i=$((i + 1)) 2278 | if [[ $i -gt 10 ]]; then die "Couldn't get dnsmasq PID" ; fi 2279 | done 2280 | DNSMASQ_PID="$(cat "$CONFDIR/dnsmasq.pid" )" 2281 | echo "dnsmasq PID: $DNSMASQ_PID" 2282 | ######(wait $DNSMASQ_PID ; die "dnsmasq failed") & # wait can't deal with non-child 2283 | pid_watchdog "$DNSMASQ_PID" 9 "dnsmasq failed" & 2284 | sleep 2 2285 | } 2286 | 2287 | check_rfkill_unblock_wifi() { 2288 | if which rfkill > /dev/null 2>&1 ; then 2289 | rfkill unblock $(rfkill | grep "$PHY" | awk '{print $1}') >/dev/null 2>&1 2290 | fi 2291 | } 2292 | 2293 | #=========== Above are functions ====================== 2294 | #=========== Executing begin ============================== 2295 | 2296 | # if empty option, show usage and exit 2297 | check_empty_option "$@" 2298 | 2299 | # TODO: are some global variables are still defined in those following code? 2300 | define_global_variables 2301 | 2302 | ARGS=( "$@" ) 2303 | 2304 | parse_user_options "$@" 2305 | # TODO: detect user option conflict 2306 | 2307 | 2308 | TMPDIR="$(decide_tmpdir)" 2309 | 2310 | # if user choose to deal with running instances, will output some info then exit after this 2311 | # NOTE above don't require root 2312 | check_other_functions 2313 | # NOTE below require root 2314 | 2315 | # if user choose to daemonize, will start new background process and exit this 2316 | daemonizing_check 2317 | 2318 | # check if wifi will work on this system and user settings 2319 | [[ $WIFI_IFACE ]] && check_wifi_settings 2320 | 2321 | [[ -n "$NEW_MACADDR" ]] && check_if_new_mac_valid # check NEW_MACADDR. will exit if not valid 2322 | 2323 | # checks finished 2324 | 2325 | ## ===== Above don't echo anything if no warning or error==================== 2326 | ## ======================================================== 2327 | phead 2328 | phead2 2329 | echo 2330 | 2331 | echo "PID: $$" 2332 | 2333 | TARGET_IFACE="$(decide_target_interface)" || exit 1 # judge wired (-i CONN_IFACE) or wireless hotspot (--ap $WIFI_IFACE) 2334 | echo "Target interface is ${TARGET_IFACE} ($(get_interface_mac "$TARGET_IFACE")) " 2335 | show_interface_pci_info "$TARGET_IFACE" 2336 | 2337 | if [[ "$MAC_USE_RANDOM" -eq 1 ]] ; then 2338 | NEW_MACADDR="$(generate_random_mac)" 2339 | echo "Use random MAC address $NEW_MACADDR" 2340 | fi 2341 | 2342 | decide_ip_addresses # ip 4 & 6 lan addresses 2343 | 2344 | # if user choose to make DHCP to tell clients to use other DNS, we don't have to serve DNS 2345 | [[ $DHCP_DNS != 'gateway' && $DHCP_DNS6 != 'gateway' ]] && dnsmasq_NO_DNS=1 2346 | 2347 | #=========================================================== 2348 | #==== begin to do some change on config files and system=== 2349 | 2350 | init_trap 2351 | # NOTE function die() is designed not to be used before init_trap() executed 2352 | 2353 | init_conf_dirs # CONFDIR , COMMON_CONFDIR . make dir 2354 | 2355 | [[ $WIFI_IFACE ]] && prepare_wifi_interface # this will create virtual ap interface (if needed) and set VWIFI_IFACE and AP_IFACE (if success) 2356 | 2357 | SUBNET_IFACE="$(decide_subnet_interface)" # SUBNET_IFACE can be TARGET_IFACE (wired) or AP_IFACE (ap) .this is after prepare_wifi_interface() 2358 | echo "$SUBNET_IFACE" > "$CONFDIR/subn_iface" 2359 | 2360 | # if virtual wifi interface, will be destroyed, so only need to save status when not 2361 | [[ -z $VWIFI_IFACE ]] && backup_interface_status 2362 | 2363 | # TODO: should these 2 before calling prepare_wifi_interface ? in check_wifi_settings() ? 2364 | # set iw country code 2365 | if [[ $WIFI_IFACE && -n "$COUNTRY" && $USE_IWCONFIG -eq 0 ]]; then 2366 | iw reg set "$COUNTRY" || die "Failed setting country code" 2367 | fi 2368 | 2369 | # judge channel availability after changing country code 2370 | if [[ $WIFI_IFACE ]] ; then 2371 | can_transmit_to_channel "${AP_IFACE}" ${CHANNEL} || die "Your adapter can not transmit to channel ${CHANNEL}, frequency band ${FREQ_BAND}GHz. (Tips: 1. Check usable channels: 'iw phy $PHY info'. 2. Check country code then check again. )" 2372 | fi 2373 | 2374 | [[ $WIFI_IFACE ]] && write_hostapd_conf 2375 | #=================================================== 2376 | #=================================================== 2377 | 2378 | # set interface unmanaged by networkManager 2379 | if is_nm_running && nm_knows "$TARGET_IFACE"; then # if nm knows target iface, should know subnet iface too. but need to wait until nm finds subnet iface (waiting code is in nm_set_unmanaged() 2380 | nm_set_unmanaged "${SUBNET_IFACE}" # will write NM_UNM_LIST 2381 | fi 2382 | 2383 | [[ $NO_DNSMASQ -eq 0 ]] && write_dnsmasq_conf 2384 | #=========================== 2385 | 2386 | # initialize subnet interface 2387 | # take subnet interface down first 2388 | ip link set down dev "${SUBNET_IFACE}" || die "Failed setting ${SUBNET_IFACE} down" 2389 | # flush old IPs of subnet interface 2390 | ip addr flush "${SUBNET_IFACE}" || die "Failed flush ${SUBNET_IFACE} IP" 2391 | 2392 | dealwith_mac # setting MAC should be after setting NM unmanaged 2393 | 2394 | [[ $WIFI_IFACE ]] && check_rfkill_unblock_wifi 2395 | 2396 | 2397 | echo 2398 | iptables --version 2399 | echo "Notice: Not showing all operations done to iptables rules" 2400 | 2401 | if [[ "$IPV6" -eq 0 ]]; then 2402 | IP_VERs=("4") 2403 | else 2404 | IP_VERs=("4" "6") 2405 | fi 2406 | 2407 | disable_unwanted_forwarding 2408 | 2409 | 2410 | # bring subnet interface up 2411 | ip link set up dev "${SUBNET_IFACE}" || die "Failed bringing ${SUBNET_IFACE} up" 2412 | 2413 | # hostapd , haveged 2414 | [[ $WIFI_IFACE ]] && run_wifi_ap_processes 2415 | 2416 | # add ipv4 address to subnet interface 2417 | ip -4 addr add ${GATEWAY4}/24 broadcast ${GATEWAY4%.*}.255 dev ${SUBNET_IFACE} || die "Failed setting ${SUBNET_IFACE} IPv4 address" 2418 | 2419 | set_ipv6_bits 2420 | 2421 | # add ipv6 address to subnet interface 2422 | if [[ $IPV6 -eq 1 ]] ; then 2423 | ip -6 addr add ${GATEWAY6}/64 dev ${SUBNET_IFACE} || die "Failed setting ${SUBNET_IFACE} IPv6 address" 2424 | fi 2425 | 2426 | 2427 | # enable Internet sharing 2428 | if [[ "$SHARE_METHOD" == "none" ]]; then 2429 | 2430 | echo "No Internet sharing" 2431 | 2432 | [[ "$BANLAN" -eq 1 ]] && start_ban_lan 2433 | 2434 | elif [[ "$SHARE_METHOD" == "nat" ]]; then 2435 | [[ "$INTERNET_IFACE" && "$dnsmasq_NO_DNS" -eq 0 ]] && echo -e "\nWARN: You specified Internet interface but this host is providing local DNS. In some unexpected case (eg. mistaken configurations), queries may leak to other interfaces, which you should be aware of.\n" >&2 2436 | 2437 | start_nat 2438 | 2439 | [[ "$BANLAN" -eq 1 ]] && start_ban_lan 2440 | 2441 | echo 1 > "/proc/sys/net/ipv4/ip_forward" || die "Failed enabling system ipv4 forwarding" # TODO maybe uneeded in '--no4' mode 2442 | 2443 | if [[ $IPV6 -eq 1 ]]; then 2444 | echo 1 > "/proc/sys/net/ipv6/conf/all/forwarding" || die "Failed enabling system ipv6 forwarding" # TODO if '-o' used, set only 2 interfaces' bits 2445 | fi 2446 | 2447 | # to enable clients to establish PPTP connections we must 2448 | # load nf_nat_pptp module 2449 | modprobe nf_nat_pptp > /dev/null 2>&1 && echo "Loaded kernel module nf_nat_pptp" 2450 | 2451 | elif [[ "$SHARE_METHOD" == "redsocks" ]]; then 2452 | 2453 | if [[ $IPV6 -eq 1 ]]; then 2454 | echo 1 > "/proc/sys/net/ipv6/conf/$SUBNET_IFACE/forwarding" || die "Failed enabling $SUBNET_IFACE ipv6 forwarding" # to set NA router bit 2455 | fi 2456 | 2457 | [[ "$dnsmasq_NO_DNS" -eq 0 && ! $DNS ]] && echo -e "\nWARN: You are using in transparent proxy mode but this host is providing local DNS. In some unexpected case (eg. mistaken configurations), queries may leak to other interfaces, which you should be aware of.\n" >&2 2458 | 2459 | [[ "$BANLAN" -eq 1 ]] && start_ban_lan 2460 | 2461 | start_redsocks 2462 | fi 2463 | 2464 | # start dhcp + dns (optional) 2465 | 2466 | # allow dns port input even if we don't run dnsmasq 2467 | # user can serve their own dns server 2468 | [[ "$DHCP_DNS" == "gateway" || "$DHCP_DNS6" == "gateway" ]] && allow_dns_port 2469 | 2470 | [[ "$CATCH_DNS" -eq 1 ]] && start_catch_dns 2471 | 2472 | [[ $NO_DNSMASQ -eq 0 ]] && ( allow_dhcp ; start_dnsmasq ) 2473 | 2474 | 2475 | echo "" 2476 | is_firewalld_running && firewalld_addto_tmptrustedzone 2477 | 2478 | 2479 | echo 2480 | echo "== Setting up completed, now linux-router should be working ==" 2481 | 2482 | #============================================================ 2483 | #============================================================ 2484 | #============================================================ 2485 | 2486 | show_qr() { 2487 | local T S P H 2488 | S="$SSID" 2489 | if [[ -n "$PASSPHRASE" ]]; then 2490 | T="WPA" 2491 | P="$PASSPHRASE" 2492 | else 2493 | T="nopass" 2494 | fi 2495 | [[ "$HIDDEN" -eq 1 ]] && H="true" 2496 | echo "Scan QR code on phone to connect to WiFi" 2497 | qrencode -m 2 -t ANSIUTF8 "WIFI:T:${T};S:${S};P:${P};H:${H};" 2498 | echo "Use this command to save QR code to image file:" 2499 | echo " qrencode -m 2 -o \"WIFI:T:${T};S:${S};P:${P};H:${H};\"" 2500 | echo 2501 | } 2502 | 2503 | [[ "$QR" -eq 1 ]] && show_qr 2504 | 2505 | # need loop to keep this script running 2506 | bash -c "while :; do sleep 8000 ; done " & 2507 | KEEP_RUNNING_PID=$! 2508 | echo "$KEEP_RUNNING_PID" > "$CONFDIR/keep_running.pid" 2509 | wait "$KEEP_RUNNING_PID" 2510 | 2511 | clean_exit 2512 | --------------------------------------------------------------------------------