Full Code of wangyu-/udp2raw for AI

unified 4208db6e27c4 cached
99 files
1.5 MB
535.5k tokens
833 symbols
1 requests
Download .txt
Showing preview only (1,576K chars total). Download the full file or copy to clipboard to get everything.
Repository: wangyu-/udp2raw
Branch: unified
Commit: 4208db6e27c4
Files: 99
Total size: 1.5 MB

Directory structure:
gitextract_9hxphtn3/

├── .clang-format
├── .gitattributes
├── CMakeLists.txt
├── ISSUE_TEMPLATE.md
├── LICENSE.md
├── README.md
├── client.cpp
├── common.cpp
├── common.h
├── connection.cpp
├── connection.h
├── doc/
│   ├── README.zh-cn.md
│   ├── android_guide.md
│   ├── build_guide.md
│   ├── build_guide.zh-cn.md
│   ├── finalspeed_step_by_step/
│   │   └── 11
│   ├── finalspeed_step_by_step.md
│   ├── kcptun_step_by_step.md
│   └── openvpn_guide.md
├── encrypt.cpp
├── encrypt.h
├── example.conf
├── fd_manager.cpp
├── fd_manager.h
├── images/
│   ├── speedtest/
│   │   └── 111
│   └── wiki/
│       └── 111
├── lib/
│   ├── aes-common.h
│   ├── aes_acc/
│   │   ├── aesacc.c
│   │   ├── aesarm.c
│   │   ├── aesarm.h
│   │   ├── aesarm_table.h
│   │   ├── aesni.c
│   │   ├── aesni.h
│   │   └── asm/
│   │       ├── arm.S
│   │       ├── arm64.S
│   │       ├── arm_arch.h
│   │       ├── mips.S
│   │       ├── mips_be.S
│   │       ├── x64.S
│   │       └── x86.S
│   ├── aes_faster_c/
│   │   ├── aes.cpp
│   │   ├── aes.h
│   │   └── wrapper.cpp
│   ├── md5.cpp
│   ├── md5.h
│   ├── pbkdf2-sha1.cpp
│   ├── pbkdf2-sha1.h
│   ├── pbkdf2-sha256.cpp
│   └── pbkdf2-sha256.h
├── libev/
│   ├── CVS/
│   │   ├── Entries
│   │   ├── Repository
│   │   └── Root
│   ├── Changes
│   ├── LICENSE
│   ├── Makefile.am
│   ├── README
│   ├── README.embed
│   ├── Symbols.ev
│   ├── Symbols.event
│   ├── autogen.sh
│   ├── configure.ac
│   ├── ev++.h
│   ├── ev.3
│   ├── ev.c
│   ├── ev.h
│   ├── ev.pod
│   ├── ev_epoll.c
│   ├── ev_kqueue.c
│   ├── ev_poll.c
│   ├── ev_port.c
│   ├── ev_select.c
│   ├── ev_vars.h
│   ├── ev_win32.c
│   ├── ev_wrap.h
│   ├── event.c
│   ├── event.h
│   ├── event_compat.h
│   ├── import_libevent
│   ├── libev.m4
│   ├── update_ev_c
│   ├── update_ev_wrap
│   └── update_symbols
├── log.cpp
├── log.h
├── main.cpp
├── makefile
├── misc.cpp
├── misc.h
├── my_ev.cpp
├── my_ev.h
├── my_ev_common.h
├── network.cpp
├── network.h
├── pcap_wrapper.cpp
├── pcap_wrapper.h
├── server.cpp
└── third-party/
    ├── luci-app-udp2raw/
    │   └── moved_to_new_repo
    ├── udp2raw-cmake-makefile/
    │   └── CMakeLists.txt
    └── udp2raw-openwrt-makefile/
        └── moved_to_new_repo

================================================
FILE CONTENTS
================================================

================================================
FILE: .clang-format
================================================
SortIncludes: false
BasedOnStyle: Google
ColumnLimit: 0
IndentWidth: 4


================================================
FILE: .gitattributes
================================================
lib/aes_acc/asm/* linguist-vendored


================================================
FILE: CMakeLists.txt
================================================
#note: experimental
#      currently only used for generating `compile_commands.json` for clangd.
#      to build this project, it's suggested to use `makefile` instead

cmake_minimum_required(VERSION 3.7)
project(udp2raw)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

set(CMAKE_CXX_STANDARD 11)

set(SOURCE_FILES
        main.cpp 
        lib/md5.cpp
        lib/pbkdf2-sha1.cpp
        lib/pbkdf2-sha256.cpp
        encrypt.cpp
        log.cpp
        network.cpp
        common.cpp
        connection.cpp
        misc.cpp
        fd_manager.cpp
        client.cpp
        server.cpp
        lib/aes_faster_c/aes.cpp
        lib/aes_faster_c/wrapper.cpp
        my_ev.cpp
)
set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused-variable -Wno-unused-parameter -Wno-missing-field-initializers -O2 -g -fsanitize=address,undefined")

add_executable(udp2raw ${SOURCE_FILES})
target_link_libraries(udp2raw rt)
target_link_libraries(udp2raw pthread)
include_directories(SYSTEM "libev")
include_directories(".")


================================================
FILE: ISSUE_TEMPLATE.md
================================================
English Only.


================================================
FILE: LICENSE.md
================================================
MIT License

Copyright (c) 2017 Yu Wang (wangyucn at gmail.com)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# Udp2raw-tunnel


A Tunnel which turns UDP Traffic into Encrypted FakeTCP/UDP/ICMP Traffic by using Raw Socket, helps you Bypass UDP FireWalls(or Unstable UDP Environment).

When used alone,udp2raw tunnels only UDP traffic. Nevertheless,if you used udp2raw + any UDP-based VPN together,you can tunnel any traffic(include TCP/UDP/ICMP),currently OpenVPN/L2TP/ShadowVPN and [tinyfecVPN](https://github.com/wangyu-/tinyfecVPN) are confirmed to be supported.


![image0](images/image0.PNG)

or

![image_vpn](images/udp2rawopenvpn.PNG)

[udp2raw wiki](https://github.com/wangyu-/udp2raw-tunnel/wiki)

[简体中文](/doc/README.zh-cn.md)


# Support Platforms
Linux host (including desktop Linux,Android phone/tablet,OpenWRT router,or Raspberry PI) with root account or cap_net_raw capability.

For Windows and MacOS users, use the udp2raw in [this repo](https://github.com/wangyu-/udp2raw-multiplatform).

# Features
### Send/Receive UDP Packets with ICMP/FakeTCP/UDP headers
ICMP/FakeTCP headers help you bypass UDP blocking, UDP QOS or improper UDP NAT behavior on some ISPs. In ICMP header mode,udp2raw works like an ICMP tunnel.

UDP headers are also supported. In UDP header mode, it behaves just like a normal UDP tunnel, and you can just make use of the other features (such as encryption, anti-replay, or connection stabilization).

### Simulated TCP with Real-time/Out-of-Order Delivery
In FakeTCP header mode,udp2raw simulates 3-way handshake while establishing a connection,simulates seq and ack_seq while data transferring. It also simulates a few TCP options such as: `MSS`, `sackOk`, `TS`, `TS_ack`, `wscale`. Firewalls will regard FakeTCP as a TCP connection, but its essentially UDP: it supports real-time/out-of-order delivery(just as normal UDP does), no congestion control or re-transmission. So there wont be any TCP over TCP problem when using OpenVPN.

### Encryption, Anti-Replay
* Encrypt your traffic with AES-128-CBC.
* Protect data integrity by HMAC-SHA1 (or weaker MD5/CRC32).
* Defense replay attack with anti-replay window.

[Notes on encryption](https://github.com/wangyu-/udp2raw-tunnel/wiki/Notes-on-encryption)

### Failure Dectection & Stabilization (Connection Recovery)
Conection failures are detected by heartbeats. If timed-out, client will automatically change port number and reconnect. If reconnection is successful, the previous connection will be recovered, and all existing UDP conversations will stay vaild.

For example, if you use udp2raw + OpenVPN, OpenVPN won't lose connection after any reconnect, **even if network cable is re-plugged or WiFi access point is changed**.

### Other Features
* **Multiplexing** One client can handle multiple UDP connections, all of which share the same raw connection.

* **Multiple Clients** One server can have multiple clients.

* **NAT Support** All of the 3 modes work in NAT environments.

* **OpenVZ Support** Tested on BandwagonHost VPS.

* **Easy to Build** No dependencies.To cross-compile udp2raw,all you need to do is just to download a toolchain,modify makefile to point at the toolchain,run `make cross` then everything is done.(Note:Pre-compiled binaries for Desktop,RaspberryPi,Android,some Openwrt Routers are already included in [Releases](https://github.com/wangyu-/udp2raw-tunnel/releases))

### Keywords
`Bypass UDP QoS` `Bypass UDP Blocking` `Bypass OpenVPN TCP over TCP problem` `OpenVPN over ICMP` `UDP to ICMP tunnel` `UDP to TCP tunnel` `UDP over ICMP` `UDP over TCP`

# Getting Started
### Installing
Download binary release from https://github.com/wangyu-/udp2raw-tunnel/releases

### Running
Assume your UDP is blocked or being QOS-ed or just poorly supported. Assume your server ip is 44.55.66.77, you have a service listening on udp port 7777.

```bash
# Run at server side:
./udp2raw_amd64 -s -l0.0.0.0:4096 -r 127.0.0.1:7777    -k "passwd" --raw-mode faketcp -a

# Run at client side
./udp2raw_amd64 -c -l0.0.0.0:3333  -r44.55.66.77:4096  -k "passwd" --raw-mode faketcp -a
```
(The above commands need to be run as root. For better security, with some extra steps, you can run udp2raw as non-root. Check [this link](https://github.com/wangyu-/udp2raw-tunnel/wiki/run-udp2raw-as-non-root) for more info  )

###### Server Output:
![](images/output_server.PNG)
###### Client Output:
![](images/output_client.PNG)

Now,an encrypted raw tunnel has been established between client and server through TCP port 4096. Connecting to UDP port 3333 at the client side is equivalent to connecting to port 7777 at the server side. No UDP traffic will be exposed.

### Note
To run on Android, check [Android_Guide](https://github.com/wangyu-/udp2raw/wiki/Android-Guide)

`-a` option automatically adds an iptables rule (or a few iptables rules) for you, udp2raw relies on this iptables rule to work stably. Be aware you dont forget `-a` (its a common mistake). If you dont want udp2raw to add iptables rule automatically, you can add it manually(take a look at `-g` option) and omit `-a`.


# Advanced Topic
### Usage
```
udp2raw-tunnel
git version:4623f878e0    build date:Nov  3 2024 23:15:46
repository: https://github.com/wangyu-/udp2raw-tunnel

usage:
    run as client : ./this_program -c -l local_listen_ip:local_port -r server_address:server_port  [options]
    run as server : ./this_program -s -l server_listen_ip:server_port -r remote_address:remote_port  [options]

common options,these options must be same on both side:
    --raw-mode            <string>        available values:faketcp(default),udp,icmp and easy-faketcp
    -k,--key              <string>        password to gen symetric key,default:"secret key"
    --cipher-mode         <string>        available values:aes128cfb,aes128cbc(default),xor,none
    --auth-mode           <string>        available values:hmac_sha1,md5(default),crc32,simple,none
    -a,--auto-rule                        auto add (and delete) iptables rule
    -g,--gen-rule                         generate iptables rule then exit,so that you can copy and
                                          add it manually.overrides -a
    --disable-anti-replay                 disable anti-replay,not suggested
    --fix-gro                             try to fix huge packet caused by GRO. this option is at an early stage.
                                          make sure client and server are at same version.
client options:
    --source-ip           <ip>            force source-ip for raw socket
    --source-port         <port>          force source-port for raw socket,tcp/udp only
                                          this option disables port changing while re-connecting
other options:
    --conf-file           <string>        read options from a configuration file instead of command line.
                                          check example.conf in repo for format
    --fifo                <string>        use a fifo(named pipe) for sending commands to the running program,
                                          check readme.md in repository for supported commands.
    --log-level           <number>        0:never    1:fatal   2:error   3:warn
                                          4:info (default)     5:debug   6:trace
    --log-position                        enable file name,function name,line number in log
    --disable-color                       disable log color
    --disable-bpf                         disable the kernel space filter,most time its not necessary
                                          unless you suspect there is a bug
    --dev                 <string>        bind raw socket to a device, not necessary but improves performance
    --sock-buf            <number>        buf size for socket,>=10 and <=10240,unit:kbyte,default:1024
    --force-sock-buf                      bypass system limitation while setting sock-buf
    --seq-mode            <number>        seq increase mode for faketcp:
                                          0:static header,do not increase seq and ack_seq
                                          1:increase seq for every packet,simply ack last seq
                                          2:increase seq randomly, about every 3 packets,simply ack last seq
                                          3:simulate an almost real seq/ack procedure(default)
                                          4:similiar to 3,but do not consider TCP Option Window_Scale,
                                          maybe useful when firewall doesnt support TCP Option
    --lower-level         <string>        send packets at OSI level 2, format:'if_name#dest_mac_adress'
                                          ie:'eth0#00:23:45:67:89:b9'.or try '--lower-level auto' to obtain
                                          the parameter automatically,specify it manually if 'auto' failed
    --wait-lock                           wait for xtables lock while invoking iptables, need iptables v1.4.20+
    --gen-add                             generate iptables rule and add it permanently,then exit.overrides -g
    --keep-rule                           monitor iptables and auto re-add if necessary.implys -a
    --hb-len              <number>        length of heart-beat packet, >=0 and <=1500
    --mtu-warn            <number>        mtu warning threshold, unit:byte, default:1375
    --clear                               clear any iptables rules added by this program.overrides everything
    --retry-on-error                      retry on error, allow to start udp2raw before network is initialized
    -h,--help                             print this help message
```

### Iptables rules,`-a` and `-g`
This program sends packets via raw socket. In FakeTCP mode, Linux kernel TCP packet processing has to be blocked by a iptables rule on both sides, otherwise the kernel will automatically send RST for an unrecongized TCP packet and you will sustain from stability / peformance problems. You can use `-a` option to let the program automatically add / delete iptables rule on start / exit. You can also use the `-g` option to generate iptables rule and add it manually.

### `--cipher-mode` and `--auth-mode`
It is suggested to use `aes128cbc` + `hmac_sha1` to obtain maximum security. If you want to run the program on a router, you can try `xor` + `simple`, which can fool packet inspection by firewalls the most of time, but it cannot protect you from serious attacks. Mode none is only for debugging purpose. It is not recommended to set the cipher-mode or auth-mode to none.

### `--seq-mode`
The FakeTCP mode does not behave 100% like a real tcp connection. ISPs may be able to distinguish the simulated tcp traffic from the real TCP traffic (though it's costly). seq-mode can help you change the seq increase behavior slightly. If you experience connection problems, try to change the value.

### `--lower-level`
`--lower-level` allows you to send packet at OSI level 2(link level),so that you can bypass any local iptables rules. If you have a complicated iptables rules which conflicts with udp2raw and you cant(or too lazy to) edit the iptables rules,`--lower-level` can be very useful. Try `--lower-level auto` to auto detect the parameters,you can specify it manually if `auto` fails.

Manual format `if_name#dest_mac_adress`,ie:`eth0#00:23:45:67:89:b9`.

### `--keep-rule`
Monitor iptables and auto re-add iptables rules(for blocking kernel tcp processing) if necessary.Especially useful when iptables rules may be cleared by other programs(for example,if you are using openwrt,everytime you changed and commited a setting,iptables rule may be cleared and re-constructed).

### `--conf-file`

You can also load options from a configuration file in order to keep secrets away from `ps` command.

For example, rewrite the options for the above `server` example (in Getting Started section) into configuration file:

`server.conf`

```
-s
# You can add comments like this
# Comments MUST occupy an entire line
# Or they will not work as expected
# Listen address
-l 0.0.0.0:4096
# Remote address
-r 127.0.0.1:7777
-a
-k passwd
--raw-mode faketcp
```

Pay attention to the `-k` parameter: In command line mode the quotes around the password will be removed by shell. In configuration files we do not remove quotes.

Then start the server with

```bash
./udp2raw_amd64 --conf-file server.conf
```

### `--fifo`
Use a fifo(named pipe) for sending commands to the running program. For example `--fifo fifo.file`.

At client side,you can use `echo reconnect >fifo.file` to force client to reconnect.Currently no command has been implemented for server.

# Peformance Test
#### Test method:
iperf3 TCP via OpenVPN + udp2raw
(iperf3 UDP mode is not used because of a bug mentioned in this issue: https://github.com/esnet/iperf/issues/296 . Instead, we package the TCP traffic into UDP by OpenVPN to test the performance. Read [Application](https://github.com/wangyu-/udp2raw-tunnel#application) for details.

#### iperf3 command:
```
iperf3 -c 10.222.2.1 -P40
iperf3 -c 10.222.2.1 -P40 -R
```
#### Environments
* **Client** Vultr $2.5/monthly plan (single core 2.4GHz cpu, 512MB RAM, Tokyo, Japan)
* **Server** BandwagonHost $3.99/annually plan (single core 2.0GHz cpu, 128MB RAM, Los Angeles, USA)

### Test1
raw_mode: faketcp  cipher_mode: xor  auth_mode: simple

![image4](images/image4.PNG)

(reverse speed was simliar and not uploaded)

### Test2
raw_mode: faketcp  cipher_mode: aes128cbc  auth_mode: md5

![image5](images/image5.PNG)

(reverse speed was simliar and not uploaded)

# wiki

Check wiki for more info:

https://github.com/wangyu-/udp2raw-tunnel/wiki


================================================
FILE: client.cpp
================================================
#include "common.h"
#include "network.h"
#include "connection.h"
#include "misc.h"
#include "log.h"
#include "lib/md5.h"
#include "encrypt.h"
#include "fd_manager.h"

#ifdef UDP2RAW_MP
u32_t detect_interval = 1500;
u64_t laste_detect_time = 0;

int use_udp_for_detection = 0;
int use_tcp_for_detection = 1;

extern pcap_t *pcap_handle;

extern int pcap_captured_full_len;
#endif

int client_on_timer(conn_info_t &conn_info)  // for client. called when a timer is ready in epoll
{
    packet_info_t &send_info = conn_info.raw_info.send_info;
    packet_info_t &recv_info = conn_info.raw_info.recv_info;
    raw_info_t &raw_info = conn_info.raw_info;
    conn_info.blob->conv_manager.c.clear_inactive();
    mylog(log_trace, "timer!\n");

    mylog(log_trace, "roller my %d,oppsite %d,%lld\n", int(conn_info.my_roller), int(conn_info.oppsite_roller), conn_info.last_oppsite_roller_time);

    mylog(log_trace, "<client_on_timer,send_info.ts_ack= %u>\n", send_info.ts_ack);

#ifdef UDP2RAW_MP
    // mylog(log_debug,"pcap cnt :%d\n",pcap_cnt);
    if (send_with_pcap && !pcap_header_captured) {
        if (get_current_time() - laste_detect_time > detect_interval) {
            laste_detect_time = get_current_time();
        } else {
            return 0;
        }
        /*
                        struct sockaddr_in remote_addr_in={0};

                        socklen_t slen = sizeof(sockaddr_in);
                        int port=get_true_random_number()%65534+1;
                        remote_addr_in.sin_family = AF_INET;
                        remote_addr_in.sin_port = htons(port);
                        remote_addr_in.sin_addr.s_addr = remote_ip_uint32;*/
        int port = get_true_random_number() % 65534 + 1;
        address_t tmp_addr = remote_addr;
        tmp_addr.set_port(port);

        if (use_udp_for_detection) {
            int new_udp_fd = socket(tmp_addr.get_type(), SOCK_DGRAM, IPPROTO_UDP);
            if (new_udp_fd < 0) {
                mylog(log_warn, "create new_udp_fd error\n");
                return -1;
            }
            setnonblocking(new_udp_fd);
            u64_t tmp = get_true_random_number();

            int ret = sendto(new_udp_fd, (char *)(&tmp), sizeof(tmp), 0, (struct sockaddr *)&tmp_addr.inner, tmp_addr.get_len());
            if (ret == -1) {
                mylog(log_warn, "sendto() failed\n");
            }
            sock_close(new_udp_fd);
        }

        if (use_tcp_for_detection) {
            static int last_tcp_fd = -1;

            int new_tcp_fd = socket(tmp_addr.get_type(), SOCK_STREAM, IPPROTO_TCP);
            if (new_tcp_fd < 0) {
                mylog(log_warn, "create new_tcp_fd error\n");
                return -1;
            }
            setnonblocking(new_tcp_fd);
            connect(new_tcp_fd, (struct sockaddr *)&tmp_addr.inner, tmp_addr.get_len());
            if (last_tcp_fd != -1)
                sock_close(last_tcp_fd);
            last_tcp_fd = new_tcp_fd;
            // close(new_tcp_fd);
        }

        mylog(log_info, "waiting for a use-able packet to be captured\n");

        return 0;
    }
#endif
    if (raw_info.disabled) {
        conn_info.state.client_current_state = client_idle;
        conn_info.my_id = get_true_random_number_nz();

        mylog(log_info, "state back to client_idle\n");
    }

    if (conn_info.state.client_current_state == client_idle) {
        raw_info.rst_received = 0;
        raw_info.disabled = 0;

        fail_time_counter++;
        if (max_fail_time > 0 && fail_time_counter > max_fail_time) {
            mylog(log_fatal, "max_fail_time exceed\n");
            myexit(-1);
        }

        conn_info.blob->anti_replay.re_init();
        conn_info.my_id = get_true_random_number_nz();  /// todo no need to do this everytime

        address_t tmp_addr;
        // u32_t new_ip=0;
        if (!force_source_ip) {
            if (get_src_adress2(tmp_addr, remote_addr) != 0) {
                mylog(log_warn, "get_src_adress() failed\n");
                return -1;
            }
            // source_addr=new_addr;
            // source_addr.set_port(0);

            mylog(log_info, "source_addr is now %s\n", tmp_addr.get_ip());

            /*
            if(new_ip!=source_ip_uint32)
            {
                    mylog(log_info,"source ip changed from %s to ",my_ntoa(source_ip_uint32));
                    log_bare(log_info,"%s\n",my_ntoa(new_ip));
                    source_ip_uint32=new_ip;
                    send_info.src_ip=new_ip;
            }*/

        } else {
            tmp_addr = source_addr;
        }

        send_info.new_src_ip.from_address_t(tmp_addr);

        if (force_source_port == 0) {
            send_info.src_port = client_bind_to_a_new_port2(bind_fd, tmp_addr);
        } else {
            send_info.src_port = source_port;
        }

        if (raw_mode == mode_icmp) {
            send_info.dst_port = send_info.src_port;
        }

        mylog(log_info, "using port %d\n", send_info.src_port);
        init_filter(send_info.src_port);

        if (raw_mode == mode_icmp || raw_mode == mode_udp) {
            conn_info.state.client_current_state = client_handshake1;

            mylog(log_info, "state changed from client_idle to client_pre_handshake\n");
        }
        if (raw_mode == mode_faketcp) {
            if (use_tcp_dummy_socket) {
                setnonblocking(bind_fd);
                int ret = connect(bind_fd, (struct sockaddr *)&remote_addr.inner, remote_addr.get_len());
                mylog(log_debug, "ret=%d,errno=%s, %d %s\n", ret, get_sock_error(), bind_fd, remote_addr.get_str());
                // mylog(log_info,"ret=%d,errno=,%d %s\n",ret,bind_fd,remote_addr.get_str());
                conn_info.state.client_current_state = client_tcp_handshake_dummy;
                mylog(log_info, "state changed from client_idle to client_tcp_handshake_dummy\n");
            } else {
                conn_info.state.client_current_state = client_tcp_handshake;
                mylog(log_info, "state changed from client_idle to client_tcp_handshake\n");
            }
        }
        conn_info.last_state_time = get_current_time();
        conn_info.last_hb_sent_time = 0;
        // dont return;
    }
    if (conn_info.state.client_current_state == client_tcp_handshake)  // send and resend syn
    {
        assert(raw_mode == mode_faketcp);
        if (get_current_time() - conn_info.last_state_time > client_handshake_timeout) {
            conn_info.state.client_current_state = client_idle;
            mylog(log_info, "state back to client_idle from client_tcp_handshake\n");
            return 0;

        } else if (get_current_time() - conn_info.last_hb_sent_time > client_retry_interval) {
            if (raw_mode == mode_faketcp) {
                if (conn_info.last_hb_sent_time == 0) {
                    send_info.psh = 0;
                    send_info.syn = 1;
                    send_info.ack = 0;
                    send_info.ts_ack = 0;
                    send_info.seq = get_true_random_number();
                    send_info.ack_seq = get_true_random_number();
                }
            }

            send_raw0(raw_info, 0, 0);

            conn_info.last_hb_sent_time = get_current_time();
            mylog(log_info, "(re)sent tcp syn\n");
            return 0;
        } else {
            return 0;
        }
        return 0;
    } else if (conn_info.state.client_current_state == client_tcp_handshake_dummy) {
        assert(raw_mode == mode_faketcp);
        if (get_current_time() - conn_info.last_state_time > client_handshake_timeout) {
            conn_info.state.client_current_state = client_idle;
            mylog(log_info, "state back to client_idle from client_tcp_handshake_dummy\n");
            return 0;
        }
    } else if (conn_info.state.client_current_state == client_handshake1)  // send and resend handshake1
    {
        if (get_current_time() - conn_info.last_state_time > client_handshake_timeout) {
            conn_info.state.client_current_state = client_idle;
            mylog(log_info, "state back to client_idle from client_handshake1\n");
            return 0;

        } else if (get_current_time() - conn_info.last_hb_sent_time > client_retry_interval) {
            if (raw_mode == mode_faketcp) {
                if (conn_info.last_hb_sent_time == 0) {
                    send_info.seq++;
                    send_info.ack_seq = recv_info.seq + 1;
                    send_info.ts_ack = recv_info.ts;
                    raw_info.reserved_send_seq = send_info.seq;
                }
                send_info.seq = raw_info.reserved_send_seq;
                send_info.psh = 0;
                send_info.syn = 0;
                send_info.ack = 1;

                if (!use_tcp_dummy_socket)
                    send_raw0(raw_info, 0, 0);

                send_handshake(raw_info, conn_info.my_id, 0, const_id);

                send_info.seq += raw_info.send_info.data_len;
            } else {
                send_handshake(raw_info, conn_info.my_id, 0, const_id);
                if (raw_mode == mode_icmp)
                    send_info.my_icmp_seq++;
            }

            conn_info.last_hb_sent_time = get_current_time();
            mylog(log_info, "(re)sent handshake1\n");
            return 0;
        } else {
            return 0;
        }
        return 0;
    } else if (conn_info.state.client_current_state == client_handshake2) {
        if (get_current_time() - conn_info.last_state_time > client_handshake_timeout) {
            conn_info.state.client_current_state = client_idle;
            mylog(log_info, "state back to client_idle from client_handshake2\n");
            return 0;
        } else if (get_current_time() - conn_info.last_hb_sent_time > client_retry_interval) {
            if (raw_mode == mode_faketcp) {
                if (conn_info.last_hb_sent_time == 0) {
                    send_info.ack_seq = recv_info.seq + raw_info.recv_info.data_len;
                    send_info.ts_ack = recv_info.ts;
                    raw_info.reserved_send_seq = send_info.seq;
                }
                send_info.seq = raw_info.reserved_send_seq;
                send_handshake(raw_info, conn_info.my_id, conn_info.oppsite_id, const_id);
                send_info.seq += raw_info.send_info.data_len;

            } else {
                send_handshake(raw_info, conn_info.my_id, conn_info.oppsite_id, const_id);
                if (raw_mode == mode_icmp)
                    send_info.my_icmp_seq++;
            }
            conn_info.last_hb_sent_time = get_current_time();
            mylog(log_info, "(re)sent handshake2\n");
            return 0;

        } else {
            return 0;
        }
        return 0;
    } else if (conn_info.state.client_current_state == client_ready) {
        fail_time_counter = 0;
        mylog(log_trace, "time %llu,%llu\n", get_current_time(), conn_info.last_state_time);

        if (get_current_time() - conn_info.last_hb_recv_time > client_conn_timeout) {
            conn_info.state.client_current_state = client_idle;
            conn_info.my_id = get_true_random_number_nz();
            mylog(log_info, "state back to client_idle from  client_ready bc of server-->client direction timeout\n");
            return 0;
        }

        if (get_current_time() - conn_info.last_oppsite_roller_time > client_conn_uplink_timeout) {
            conn_info.state.client_current_state = client_idle;
            conn_info.my_id = get_true_random_number_nz();
            mylog(log_info, "state back to client_idle from  client_ready bc of client-->server direction timeout\n");
        }

        if (get_current_time() - conn_info.last_hb_sent_time < heartbeat_interval) {
            return 0;
        }

        mylog(log_debug, "heartbeat sent <%x,%x>\n", conn_info.oppsite_id, conn_info.my_id);

        if (hb_mode == 0)
            send_safer(conn_info, 'h', hb_buf, 0);  /////////////send
        else
            send_safer(conn_info, 'h', hb_buf, hb_len);
        conn_info.last_hb_sent_time = get_current_time();
        return 0;
    } else {
        mylog(log_fatal, "unknown state,this shouldnt happen.\n");
        myexit(-1);
    }
    return 0;
}
int client_on_raw_recv_hs2_or_ready(conn_info_t &conn_info, char type, char *data, int data_len) {
    packet_info_t &send_info = conn_info.raw_info.send_info;
    packet_info_t &recv_info = conn_info.raw_info.recv_info;

    if (!recv_info.new_src_ip.equal(send_info.new_dst_ip) || recv_info.src_port != send_info.dst_port) {
        mylog(log_warn, "unexpected adress %s %s %d %d,this shouldnt happen.\n", recv_info.new_src_ip.get_str1(), send_info.new_dst_ip.get_str2(), recv_info.src_port, send_info.dst_port);
        return -1;
    }

    if (conn_info.state.client_current_state == client_handshake2) {
        mylog(log_info, "changed state from to client_handshake2 to client_ready\n");
        conn_info.state.client_current_state = client_ready;
        conn_info.last_hb_sent_time = 0;
        conn_info.last_hb_recv_time = get_current_time();
        conn_info.last_oppsite_roller_time = conn_info.last_hb_recv_time;
        client_on_timer(conn_info);
    }
    if (data_len >= 0 && type == 'h') {
        mylog(log_debug, "[hb]heart beat received,oppsite_roller=%d\n", int(conn_info.oppsite_roller));
        conn_info.last_hb_recv_time = get_current_time();
        return 0;
    } else if (data_len >= int(sizeof(u32_t)) && type == 'd') {
        mylog(log_trace, "received a data from fake tcp,len:%d\n", data_len);

        if (hb_mode == 0)
            conn_info.last_hb_recv_time = get_current_time();

        u32_t tmp_conv_id;
        memcpy(&tmp_conv_id, &data[0], sizeof(tmp_conv_id));
        tmp_conv_id = ntohl(tmp_conv_id);

        if (!conn_info.blob->conv_manager.c.is_conv_used(tmp_conv_id)) {
            mylog(log_info, "unknow conv %d,ignore\n", tmp_conv_id);
            return 0;
        }

        conn_info.blob->conv_manager.c.update_active_time(tmp_conv_id);

        // u64_t u64=conn_info.blob->conv_manager.c.find_data_by_conv(tmp_conv_id);
        address_t tmp_addr = conn_info.blob->conv_manager.c.find_data_by_conv(tmp_conv_id);

        // sockaddr_in tmp_sockaddr={0};

        // tmp_sockaddr.sin_family = AF_INET;
        // tmp_sockaddr.sin_addr.s_addr=(u64>>32u);

        // tmp_sockaddr.sin_port= htons(uint16_t((u64<<32u)>>32u));

        int ret = sendto(udp_fd, data + sizeof(u32_t), data_len - (sizeof(u32_t)), 0, (struct sockaddr *)&tmp_addr.inner, tmp_addr.get_len());

        if (ret < 0) {
            mylog(log_warn, "sento returned %d,%s,%02x,%s\n", ret, get_sock_error(), int(tmp_addr.get_type()), tmp_addr.get_str());
            // perror("ret<0");
        }
    } else {
        mylog(log_warn, "unknown packet,this shouldnt happen.\n");
        return -1;
    }
    return 0;
}
int client_on_raw_recv(conn_info_t &conn_info)  // called when raw fd received a packet.
{
    char *data;
    int data_len;
    packet_info_t &send_info = conn_info.raw_info.send_info;
    packet_info_t &recv_info = conn_info.raw_info.recv_info;

    raw_info_t &raw_info = conn_info.raw_info;

    mylog(log_trace, "<client_on_raw_recv,send_info.ts_ack= %u>\n", send_info.ts_ack);

#ifdef UDP2RAW_LINUX
    if (pre_recv_raw_packet() < 0) return -1;
#endif

    if (conn_info.state.client_current_state == client_idle) {
        discard_raw_packet();
        // recv(raw_recv_fd, 0,0, 0  );
    } else if (conn_info.state.client_current_state == client_tcp_handshake || conn_info.state.client_current_state == client_tcp_handshake_dummy)  // received syn ack
    {
        assert(raw_mode == mode_faketcp);
        if (recv_raw0(raw_info, data, data_len) < 0) {
            return -1;
        }
        if (data_len >= max_data_len + 1) {
            mylog(log_debug, "data_len=%d >= max_data_len+1,ignored", data_len);
            return -1;
        }
        if (!recv_info.new_src_ip.equal(send_info.new_dst_ip) || recv_info.src_port != send_info.dst_port) {
            mylog(log_debug, "unexpected adress %s %s %d %d\n", recv_info.new_src_ip.get_str1(), send_info.new_dst_ip.get_str2(), recv_info.src_port, send_info.dst_port);
            return -1;
        }
        if (data_len == 0 && raw_info.recv_info.syn == 1 && raw_info.recv_info.ack == 1) {
            if (conn_info.state.client_current_state == client_tcp_handshake) {
                if (recv_info.ack_seq != send_info.seq + 1) {
                    mylog(log_debug, "seq ack_seq mis match\n");
                    return -1;
                }
                mylog(log_info, "state changed from client_tcp_handshake to client_handshake1\n");
            } else {
                send_info.seq = recv_info.ack_seq - 1;
                mylog(log_info, "state changed from client_tcp_dummy to client_handshake1\n");
                // send_info.ack_seq=recv_info.seq+1;
            }
            conn_info.state.client_current_state = client_handshake1;

            conn_info.last_state_time = get_current_time();
            conn_info.last_hb_sent_time = 0;
            client_on_timer(conn_info);
            return 0;
        } else {
            mylog(log_debug, "unexpected packet type,expected:syn ack\n");
            return -1;
        }
    } else if (conn_info.state.client_current_state == client_handshake1)  // recevied respond of handshake1
    {
        if (recv_bare(raw_info, data, data_len) != 0) {
            mylog(log_debug, "recv_bare failed!\n");
            return -1;
        }
        if (!recv_info.new_src_ip.equal(send_info.new_dst_ip) || recv_info.src_port != send_info.dst_port) {
            mylog(log_debug, "unexpected adress %s %s %d %d\n", recv_info.new_src_ip.get_str1(), send_info.new_dst_ip.get_str2(), recv_info.src_port, send_info.dst_port);
            return -1;
        }
        if (data_len < int(3 * sizeof(my_id_t))) {
            mylog(log_debug, "too short to be a handshake\n");
            return -1;
        }
        my_id_t tmp_oppsite_id;
        memcpy(&tmp_oppsite_id, &data[0], sizeof(tmp_oppsite_id));
        tmp_oppsite_id = ntohl(tmp_oppsite_id);

        my_id_t tmp_my_id;
        memcpy(&tmp_my_id, &data[sizeof(my_id_t)], sizeof(tmp_my_id));
        tmp_my_id = ntohl(tmp_my_id);

        my_id_t tmp_oppsite_const_id;
        memcpy(&tmp_oppsite_const_id, &data[sizeof(my_id_t) * 2], sizeof(tmp_oppsite_const_id));
        tmp_oppsite_const_id = ntohl(tmp_oppsite_const_id);

        if (tmp_my_id != conn_info.my_id) {
            mylog(log_debug, "tmp_my_id doesnt match\n");
            return -1;
        }

        if (raw_mode == mode_faketcp) {
            if (recv_info.ack_seq != send_info.seq) {
                mylog(log_debug, "seq ack_seq mis match\n");
                return -1;
            }
            if (recv_info.seq != send_info.ack_seq) {
                mylog(log_debug, "seq ack_seq mis match\n");
                return -1;
            }
        }
        conn_info.oppsite_id = tmp_oppsite_id;

        mylog(log_info, "changed state from to client_handshake1 to client_handshake2,my_id is %x,oppsite id is %x\n", conn_info.my_id, conn_info.oppsite_id);

        conn_info.state.client_current_state = client_handshake2;
        conn_info.last_state_time = get_current_time();
        conn_info.last_hb_sent_time = 0;
        client_on_timer(conn_info);

        return 0;
    } else if (conn_info.state.client_current_state == client_handshake2 || conn_info.state.client_current_state == client_ready)  // received heartbeat or data
    {
        vector<char> type_vec;
        vector<string> data_vec;
        recv_safer_multi(conn_info, type_vec, data_vec);
        if (data_vec.empty()) {
            mylog(log_debug, "recv_safer failed!\n");
            return -1;
        }

        for (int i = 0; i < (int)type_vec.size(); i++) {
            char type = type_vec[i];
            char *data = (char *)data_vec[i].c_str();  // be careful, do not append data to it
            int data_len = data_vec[i].length();
            client_on_raw_recv_hs2_or_ready(conn_info, type, data, data_len);
        }

        return 0;
    } else {
        mylog(log_fatal, "unknown state,this shouldnt happen.\n");
        myexit(-1);
    }
    return 0;
}
int client_on_udp_recv(conn_info_t &conn_info) {
    int recv_len;
    char buf[buf_len];
    address_t::storage_t udp_new_addr_in = {{0}};
    socklen_t udp_new_addr_len = sizeof(address_t::storage_t);
    if ((recv_len = recvfrom(udp_fd, buf, max_data_len + 1, 0,
                             (struct sockaddr *)&udp_new_addr_in, &udp_new_addr_len)) == -1) {
        mylog(log_debug, "recv_from error,%s\n", get_sock_error());
        return -1;
        // myexit(1);
    };

    if (recv_len == max_data_len + 1) {
        mylog(log_warn, "huge packet, data_len > %d,dropped\n", max_data_len);
        return -1;
    }

    if (recv_len >= mtu_warn) {
        mylog(log_warn, "huge packet,data len=%d (>=%d).strongly suggested to set a smaller mtu at upper level,to get rid of this warn\n ", recv_len, mtu_warn);
    }

    address_t tmp_addr;
    tmp_addr.from_sockaddr((sockaddr *)&udp_new_addr_in, udp_new_addr_len);
    u32_t conv;

    if (!conn_info.blob->conv_manager.c.is_data_used(tmp_addr)) {
        if (conn_info.blob->conv_manager.c.get_size() >= max_conv_num) {
            mylog(log_warn, "ignored new udp connect bc max_conv_num exceed\n");
            return -1;
        }
        conv = conn_info.blob->conv_manager.c.get_new_conv();
        conn_info.blob->conv_manager.c.insert_conv(conv, tmp_addr);
        mylog(log_info, "new packet from %s,conv_id=%x\n", tmp_addr.get_str(), conv);
    } else {
        conv = conn_info.blob->conv_manager.c.find_conv_by_data(tmp_addr);
    }

    conn_info.blob->conv_manager.c.update_active_time(conv);

    if (conn_info.state.client_current_state == client_ready) {
        send_data_safer(conn_info, buf, recv_len, conv);
    }
    return 0;
}
void udp_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) {
    conn_info_t &conn_info = *((conn_info_t *)watcher->data);
    client_on_udp_recv(conn_info);
}
void raw_recv_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) {
    if (is_udp2raw_mp) assert(0 == 1);
    conn_info_t &conn_info = *((conn_info_t *)watcher->data);
    client_on_raw_recv(conn_info);
}
#ifdef UDP2RAW_MP
void async_cb(struct ev_loop *loop, struct ev_async *watcher, int revents) {
    conn_info_t &conn_info = *((conn_info_t *)watcher->data);

    if (send_with_pcap && !pcap_header_captured) {
        int empty = 0;
        char *p;
        int len;
        pthread_mutex_lock(&queue_mutex);
        empty = my_queue.empty();
        if (!empty) {
            my_queue.peek_front(p, len);
            my_queue.pop_front();
        }
        pthread_mutex_unlock(&queue_mutex);
        if (empty) return;

        pcap_header_captured = 1;
        assert(pcap_link_header_len != -1);
        memcpy(pcap_header_buf, p, max_data_len);

        log_bare(log_info, "link level header captured:\n");
        unsigned char *tmp = (unsigned char *)pcap_header_buf;
        pcap_captured_full_len = len;
        for (int i = 0; i < pcap_link_header_len; i++)
            log_bare(log_info, "<%x>", (u32_t)tmp[i]);

        log_bare(log_info, "\n");
        return;
    }

    // mylog(log_info,"async_cb called\n");
    while (1) {
        int empty = 0;
        char *p;
        int len;
        pthread_mutex_lock(&queue_mutex);
        empty = my_queue.empty();
        if (!empty) {
            my_queue.peek_front(p, len);
            my_queue.pop_front();
        }
        pthread_mutex_unlock(&queue_mutex);

        if (empty) break;
        if (g_fix_gro == 0 && len > max_data_len) {
            mylog(log_warn, "huge packet %d > %d, dropped. maybe you need to turn down mtu at upper level, or maybe you need the --fix-gro option\n", len, max_data_len);
            break;
        }

        int new_len = len - pcap_link_header_len;
        memcpy(g_packet_buf, p + pcap_link_header_len, new_len);
        g_packet_buf_len = new_len;
        assert(g_packet_buf_cnt == 0);
        g_packet_buf_cnt++;
        client_on_raw_recv(conn_info);
    }
}
#endif
void clear_timer_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents) {
    conn_info_t &conn_info = *((conn_info_t *)watcher->data);
    client_on_timer(conn_info);
}
void fifo_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) {
    conn_info_t &conn_info = *((conn_info_t *)watcher->data);

    char buf[buf_len];
    int fifo_fd = watcher->fd;

    int len = read(fifo_fd, buf, sizeof(buf));
    if (len < 0) {
        mylog(log_warn, "fifo read failed len=%d,errno=%s\n", len, get_sock_error());
        return;
    }
    buf[len] = 0;
    while (len >= 1 && buf[len - 1] == '\n')
        buf[len - 1] = 0;
    mylog(log_info, "got data from fifo,len=%d,s=[%s]\n", len, buf);
    if (strcmp(buf, "reconnect") == 0) {
        mylog(log_info, "received command: reconnect\n");
        conn_info.state.client_current_state = client_idle;
        conn_info.my_id = get_true_random_number_nz();
    } else {
        mylog(log_info, "unknown command\n");
    }
}
int client_event_loop() {
    char buf[buf_len];

    conn_info_t conn_info;
    conn_info.my_id = get_true_random_number_nz();

    conn_info.prepare();
    packet_info_t &send_info = conn_info.raw_info.send_info;
    packet_info_t &recv_info = conn_info.raw_info.recv_info;

#ifdef UDP2RAW_LINUX
    if (lower_level) {
        if (lower_level_manual) {
            int index;
            init_ifindex(if_name, raw_send_fd, index);
            // init_ifindex(if_name);
            memset(&send_info.addr_ll, 0, sizeof(send_info.addr_ll));
            send_info.addr_ll.sll_family = AF_PACKET;
            send_info.addr_ll.sll_ifindex = index;
            send_info.addr_ll.sll_halen = ETHER_ADDR_LEN;
            send_info.addr_ll.sll_protocol = htons(ETH_P_IP);
            memcpy(&send_info.addr_ll.sll_addr, dest_hw_addr, ETHER_ADDR_LEN);
            mylog(log_info, "we are running at lower-level (manual) mode\n");
        } else {
            u32_t dest_ip;
            string if_name_string;
            string hw_string;
            assert(remote_addr.get_type() == AF_INET);

            if (retry_on_error == 0) {
                if (find_lower_level_info(remote_addr.inner.ipv4.sin_addr.s_addr, dest_ip, if_name_string, hw_string) != 0) {
                    mylog(log_fatal, "auto detect lower-level info failed for %s,specific it manually\n", remote_addr.get_ip());
                    myexit(-1);
                }
            } else {
                int ok = 0;
                while (!ok) {
                    if (find_lower_level_info(remote_addr.inner.ipv4.sin_addr.s_addr, dest_ip, if_name_string, hw_string) != 0) {
                        mylog(log_warn, "auto detect lower-level info failed for %s,retry in %d seconds\n", remote_addr.get_ip(), retry_on_error_interval);
                        sleep(retry_on_error_interval);
                    } else {
                        ok = 1;
                    }
                }
            }
            mylog(log_info, "we are running at lower-level (auto) mode,%s %s %s\n", my_ntoa(dest_ip), if_name_string.c_str(), hw_string.c_str());

            u32_t hw[6];
            memset(hw, 0, sizeof(hw));
            sscanf(hw_string.c_str(), "%x:%x:%x:%x:%x:%x", &hw[0], &hw[1], &hw[2],
                   &hw[3], &hw[4], &hw[5]);

            mylog(log_warn,
                  "make sure this is correct:   if_name=<%s>  dest_mac_adress=<%02x:%02x:%02x:%02x:%02x:%02x>  \n",
                  if_name_string.c_str(), hw[0], hw[1], hw[2], hw[3], hw[4], hw[5]);
            for (int i = 0; i < 6; i++) {
                dest_hw_addr[i] = uint8_t(hw[i]);
            }

            // mylog(log_fatal,"--lower-level auto for client hasnt been implemented\n");
            int index;
            init_ifindex(if_name_string.c_str(), raw_send_fd, index);

            memset(&send_info.addr_ll, 0, sizeof(send_info.addr_ll));
            send_info.addr_ll.sll_family = AF_PACKET;
            send_info.addr_ll.sll_ifindex = index;
            send_info.addr_ll.sll_halen = ETHER_ADDR_LEN;
            send_info.addr_ll.sll_protocol = htons(ETH_P_IP);
            memcpy(&send_info.addr_ll.sll_addr, dest_hw_addr, ETHER_ADDR_LEN);
            // mylog(log_info,"we are running at lower-level (manual) mode\n");
        }
    }
#endif

#ifdef UDP2RAW_MP

    address_t tmp_addr;
    if (get_src_adress2(tmp_addr, remote_addr) != 0) {
        mylog(log_error, "get_src_adress() failed\n");
        myexit(-1);
    }
    if (strcmp(dev, "") == 0) {
        mylog(log_info, "--dev have not been set, trying to detect automatically, available devices:\n");

        mylog(log_info, "available device(device name: ip address ; description):\n");

        char errbuf[PCAP_ERRBUF_SIZE];

        int found = 0;

        pcap_if_t *interfaces, *d;
        if (pcap_findalldevs(&interfaces, errbuf) == -1) {
            mylog(log_fatal, "error in pcap_findalldevs(),%s\n", errbuf);
            myexit(-1);
        }

        for (pcap_if_t *d = interfaces; d != NULL; d = d->next) {
            log_bare(log_warn, "%s:", d->name);
            int cnt = 0;
            for (pcap_addr_t *a = d->addresses; a != NULL; a = a->next) {
                if (a->addr == NULL) {
                    log_bare(log_debug, " [a->addr==NULL]");
                    continue;
                }
                if (a->addr->sa_family == AF_INET || a->addr->sa_family == AF_INET6) {
                    cnt++;

                    if (a->addr->sa_family == AF_INET) {
                        char s[max_addr_len];
                        inet_ntop(AF_INET, &((struct sockaddr_in *)a->addr)->sin_addr, s, max_addr_len);
                        log_bare(log_warn, " [%s]", s);

                        if (a->addr->sa_family == raw_ip_version) {
                            if (((struct sockaddr_in *)a->addr)->sin_addr.s_addr == tmp_addr.inner.ipv4.sin_addr.s_addr) {
                                found++;
                                strcpy(dev, d->name);
                            }
                        }
                    } else {
                        assert(a->addr->sa_family == AF_INET6);

                        char s[max_addr_len];
                        inet_ntop(AF_INET6, &((struct sockaddr_in6 *)a->addr)->sin6_addr, s, max_addr_len);
                        log_bare(log_warn, " [%s]", s);

                        if (a->addr->sa_family == raw_ip_version) {
                            if (memcmp(&((struct sockaddr_in6 *)a->addr)->sin6_addr, &tmp_addr.inner.ipv6.sin6_addr, sizeof(struct in6_addr)) == 0) {
                                found++;
                                strcpy(dev, d->name);
                            }
                        }
                    }
                } else {
                    log_bare(log_debug, " [unknow:%d]", int(a->addr->sa_family));
                }
            }
            if (cnt == 0) log_bare(log_warn, " [no ip found]");
            if (d->description == 0) {
                log_bare(log_warn, "; (no description available)");
            } else {
                log_bare(log_warn, "; %s", d->description);
            }
            log_bare(log_warn, "\n");
        }

        if (found == 0) {
            mylog(log_fatal, "no matched device found for ip: [%s]\n", tmp_addr.get_ip());
            myexit(-1);
        } else if (found == 1) {
            mylog(log_info, "using device:[%s], ip: [%s]\n", dev, tmp_addr.get_ip());
        } else {
            mylog(log_fatal, "more than one devices found for ip: [%s] , you need to use --dev manually\n", tmp_addr.get_ip());
            myexit(-1);
        }
    } else {
        mylog(log_info, "--dev has been manually set, using device:[%s]\n", dev);
    }
#endif

    send_info.src_port = 0;
    memset(&send_info.new_src_ip, 0, sizeof(send_info.new_src_ip));

    int i, j, k;
    int ret;

    send_info.new_dst_ip.from_address_t(remote_addr);
    send_info.dst_port = remote_addr.get_port();

    udp_fd = socket(local_addr.get_type(), SOCK_DGRAM, IPPROTO_UDP);
    set_buf_size(udp_fd, socket_buf_size);

    if (::bind(udp_fd, (struct sockaddr *)&local_addr.inner, local_addr.get_len()) == -1) {
        mylog(log_fatal, "socket bind error\n");
        // perror("socket bind error");
        myexit(1);
    }
    setnonblocking(udp_fd);

    // epollfd = epoll_create1(0);

    // const int max_events = 4096;
    // struct epoll_event ev, events[max_events];
    // if (epollfd < 0) {
    //	mylog(log_fatal,"epoll return %d\n", epollfd);
    //	myexit(-1);
    // }

    struct ev_loop *loop = ev_default_loop(0);
    assert(loop != NULL);

    // ev.events = EPOLLIN;
    // ev.data.u64 = udp_fd;
    // ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, udp_fd, &ev);
    // if (ret!=0) {
    //	mylog(log_fatal,"add  udp_listen_fd error\n");
    //	myexit(-1);
    // }

    struct ev_io udp_accept_watcher;

    udp_accept_watcher.data = &conn_info;
    ev_io_init(&udp_accept_watcher, udp_accept_cb, udp_fd, EV_READ);
    ev_io_start(loop, &udp_accept_watcher);

    // ev.events = EPOLLIN;
    // ev.data.u64 = raw_recv_fd;

    // ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, raw_recv_fd, &ev);
    // if (ret!= 0) {
    //	mylog(log_fatal,"add raw_fd error\n");
    //	myexit(-1);
    // }

#ifdef UDP2RAW_LINUX
    struct ev_io raw_recv_watcher;

    raw_recv_watcher.data = &conn_info;
    ev_io_init(&raw_recv_watcher, raw_recv_cb, raw_recv_fd, EV_READ);
    ev_io_start(loop, &raw_recv_watcher);
#endif

#ifdef UDP2RAW_MP
    g_default_loop = loop;
    async_watcher.data = &conn_info;
    ev_async_init(&async_watcher, async_cb);
    ev_async_start(loop, &async_watcher);

    init_raw_socket();  // must be put after dev detection
#endif

    // set_timer(epollfd,timer_fd);
    struct ev_timer clear_timer;

    clear_timer.data = &conn_info;
    ev_timer_init(&clear_timer, clear_timer_cb, 0, timer_interval / 1000.0);
    ev_timer_start(loop, &clear_timer);

    mylog(log_debug, "send_raw : from %s %d  to %s %d\n", send_info.new_src_ip.get_str1(), send_info.src_port, send_info.new_dst_ip.get_str2(), send_info.dst_port);

    int fifo_fd = -1;

    struct ev_io fifo_watcher;
    fifo_watcher.data = &conn_info;

    if (fifo_file[0] != 0) {
        fifo_fd = create_fifo(fifo_file);

        ev_io_init(&fifo_watcher, fifo_cb, fifo_fd, EV_READ);
        ev_io_start(loop, &fifo_watcher);

        mylog(log_info, "fifo_file=%s\n", fifo_file);
    }

    ev_run(loop, 0);
    return 0;
}


================================================
FILE: common.cpp
================================================
/*
 * comm.cpp
 *
 *  Created on: Jul 29, 2017
 *      Author: wangyu
 */

#include "common.h"
#include "log.h"
#include "misc.h"

#include <random>
#include <cmath>

// static int random_number_fd=-1;
int force_socket_buf = 0;

int address_t::from_str(char *str) {
    clear();

    char ip_addr_str[100];
    u32_t port;
    mylog(log_info, "parsing address: %s\n", str);
    int is_ipv6 = 0;
    if (sscanf(str, "[%[^]]]:%u", ip_addr_str, &port) == 2) {
        mylog(log_info, "its an ipv6 adress\n");
        inner.ipv6.sin6_family = AF_INET6;
        is_ipv6 = 1;
    } else if (sscanf(str, "%[^:]:%u", ip_addr_str, &port) == 2) {
        mylog(log_info, "its an ipv4 adress\n");
        inner.ipv4.sin_family = AF_INET;
    } else {
        mylog(log_error, "failed to parse\n");
        myexit(-1);
    }

    mylog(log_info, "ip_address is {%s}, port is {%u}\n", ip_addr_str, port);

    if (port > 65535) {
        mylog(log_error, "invalid port: %d\n", port);
        myexit(-1);
    }

    int ret = -100;
    if (is_ipv6) {
        ret = inet_pton(AF_INET6, ip_addr_str, &(inner.ipv6.sin6_addr));
        inner.ipv6.sin6_port = htons(port);
        if (ret == 0)  // 0 if address type doesnt match
        {
            mylog(log_error, "ip_addr %s is not an ipv6 address, %d\n", ip_addr_str, ret);
            myexit(-1);
        } else if (ret == 1)  // inet_pton returns 1 on success
        {
            // okay
        } else {
            mylog(log_error, "ip_addr %s is invalid, %d\n", ip_addr_str, ret);
            myexit(-1);
        }
    } else {
        ret = inet_pton(AF_INET, ip_addr_str, &(inner.ipv4.sin_addr));
        inner.ipv4.sin_port = htons(port);

        if (ret == 0) {
            mylog(log_error, "ip_addr %s is not an ipv4 address, %d\n", ip_addr_str, ret);
            myexit(-1);
        } else if (ret == 1) {
            // okay
        } else {
            mylog(log_error, "ip_addr %s is invalid, %d\n", ip_addr_str, ret);
            myexit(-1);
        }
    }

    return 0;
}

int address_t::from_str_ip_only(char *str) {
    clear();

    u32_t type;

    if (strchr(str, ':') == NULL)
        type = AF_INET;
    else
        type = AF_INET6;

    ((sockaddr *)&inner)->sa_family = type;

    int ret;
    if (type == AF_INET) {
        ret = inet_pton(type, str, &inner.ipv4.sin_addr);
    } else {
        ret = inet_pton(type, str, &inner.ipv6.sin6_addr);
    }

    if (ret == 0)  // 0 if address type doesnt match
    {
        mylog(log_error, "confusion in parsing %s, %d\n", str, ret);
        myexit(-1);
    } else if (ret == 1)  // inet_pton returns 1 on success
    {
        // okay
    } else {
        mylog(log_error, "ip_addr %s is invalid, %d\n", str, ret);
        myexit(-1);
    }
    return 0;
}

char *address_t::get_str() {
    static char res[max_addr_len];
    to_str(res);
    return res;
}
void address_t::to_str(char *s) {
    // static char res[max_addr_len];
    char ip_addr[max_addr_len];
    u32_t port;
    const char *ret = 0;
    if (get_type() == AF_INET6) {
        ret = inet_ntop(AF_INET6, &inner.ipv6.sin6_addr, ip_addr, max_addr_len);
        port = inner.ipv6.sin6_port;
    } else if (get_type() == AF_INET) {
        ret = inet_ntop(AF_INET, &inner.ipv4.sin_addr, ip_addr, max_addr_len);
        port = inner.ipv4.sin_port;
    } else {
        assert(0 == 1);
    }

    if (ret == 0)  // NULL on failure
    {
        mylog(log_error, "inet_ntop failed\n");
        myexit(-1);
    }

    port = ntohs(port);

    ip_addr[max_addr_len - 1] = 0;
    if (get_type() == AF_INET6) {
        sprintf(s, "[%s]:%u", ip_addr, (u32_t)port);
    } else {
        sprintf(s, "%s:%u", ip_addr, (u32_t)port);
    }

    // return res;
}

char *address_t::get_ip() {
    char ip_addr[max_addr_len];
    static char s[max_addr_len];
    const char *ret = 0;
    if (get_type() == AF_INET6) {
        ret = inet_ntop(AF_INET6, &inner.ipv6.sin6_addr, ip_addr, max_addr_len);
    } else if (get_type() == AF_INET) {
        ret = inet_ntop(AF_INET, &inner.ipv4.sin_addr, ip_addr, max_addr_len);
    } else {
        assert(0 == 1);
    }

    if (ret == 0)  // NULL on failure
    {
        mylog(log_error, "inet_ntop failed\n");
        myexit(-1);
    }

    ip_addr[max_addr_len - 1] = 0;
    if (get_type() == AF_INET6) {
        sprintf(s, "%s", ip_addr);
    } else {
        sprintf(s, "%s", ip_addr);
    }

    return s;
}

int address_t::from_sockaddr(sockaddr *addr, socklen_t slen) {
    clear();
    // memset(&inner,0,sizeof(inner));
    if (addr->sa_family == AF_INET6) {
        assert(slen == sizeof(sockaddr_in6));
        // inner.ipv6= *( (sockaddr_in6*) addr );
        memcpy(&inner, addr, slen);
    } else if (addr->sa_family == AF_INET) {
        assert(slen == sizeof(sockaddr_in));
        // inner.ipv4= *( (sockaddr_in*) addr );
        memcpy(&inner, addr, slen);
    } else {
        assert(0 == 1);
    }
    return 0;
}

int address_t::new_connected_udp_fd() {
    int new_udp_fd;
    new_udp_fd = socket(get_type(), SOCK_DGRAM, IPPROTO_UDP);
    if (new_udp_fd < 0) {
        mylog(log_warn, "create udp_fd error\n");
        return -1;
    }
    setnonblocking(new_udp_fd);
    set_buf_size(new_udp_fd, socket_buf_size);

    mylog(log_debug, "created new udp_fd %d\n", new_udp_fd);
    int ret = connect(new_udp_fd, (struct sockaddr *)&inner, get_len());
    if (ret != 0) {
        mylog(log_warn, "udp fd connect fail %d %s\n", ret, strerror(errno));
        // sock_close(new_udp_fd);
        close(new_udp_fd);
        return -1;
    }

    return new_udp_fd;
}

bool my_ip_t::equal(const my_ip_t &b) const {
    // extern int raw_ip_version;
    if (raw_ip_version == AF_INET) {
        return v4 == b.v4;
    } else if (raw_ip_version == AF_INET6) {
        return memcmp(&v6, &b.v6, sizeof(v6)) == 0;
    }
    assert(0 == 1);
    return 0;
}
char *my_ip_t::get_str1() const {
    static char res[max_addr_len];
    if (raw_ip_version == AF_INET6) {
        assert(inet_ntop(AF_INET6, &v6, res, max_addr_len) != 0);
    } else {
        assert(raw_ip_version == AF_INET);
        assert(inet_ntop(AF_INET, &v4, res, max_addr_len) != 0);
    }
    return res;
}
char *my_ip_t::get_str2() const {
    static char res[max_addr_len];
    if (raw_ip_version == AF_INET6) {
        assert(inet_ntop(AF_INET6, &v6, res, max_addr_len) != 0);
    } else {
        assert(raw_ip_version == AF_INET);
        assert(inet_ntop(AF_INET, &v4, res, max_addr_len) != 0);
    }
    return res;
}

int my_ip_t::from_address_t(address_t tmp_addr) {
    if (tmp_addr.get_type() == raw_ip_version && raw_ip_version == AF_INET) {
        v4 = tmp_addr.inner.ipv4.sin_addr.s_addr;
    } else if (tmp_addr.get_type() == raw_ip_version && raw_ip_version == AF_INET6) {
        v6 = tmp_addr.inner.ipv6.sin6_addr;
    } else {
        assert(0 == 1);
    }
    return 0;
}
/*
int my_ip_t::from_str(char * str)
{
        u32_t type;
        if(strchr(str,':')==NULL)
                type=AF_INET;
        else
                type=AF_INET6;
        int ret;
        ret=inet_pton(type, str,this);
        if(ret==0)  // 0 if address type doesnt match
        {
                mylog(log_error,"confusion in parsing %s, %d\n",str,ret);
                myexit(-1);
        }
        else if(ret==1) // inet_pton returns 1 on success
        {
                //okay
        }
        else
        {
                mylog(log_error,"ip_addr %s is invalid, %d\n",str,ret);
                myexit(-1);
        }
        return 0;
}*/
#ifdef UDP2RAW_MP

int init_ws() {
#if defined(__MINGW32__)
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;

    /* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
    wVersionRequested = MAKEWORD(2, 2);

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
        /* Tell the user that we could not find a usable */
        /* Winsock DLL.                                  */
        printf("WSAStartup failed with error: %d\n", err);
        exit(-1);
    }

    /* Confirm that the WinSock DLL supports 2.2.*/
    /* Note that if the DLL supports versions greater    */
    /* than 2.2 in addition to 2.2, it will still return */
    /* 2.2 in wVersion since that is the version we      */
    /* requested.                                        */

    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
        /* Tell the user that we could not find a usable */
        /* WinSock DLL.                                  */
        printf("Could not find a usable version of Winsock.dll\n");
        WSACleanup();
        exit(-1);
    } else {
        printf("The Winsock 2.2 dll was found okay");
    }

    int tmp[] = {0, 100, 200, 300, 500, 800, 1000, 2000, 3000, 4000, -1};
    int succ = 0;
    for (int i = 1; tmp[i] != -1; i++) {
        if (_setmaxstdio(100) == -1)
            break;
        else
            succ = i;
    }
    printf(", _setmaxstdio() was set to %d\n", tmp[succ]);
#endif
    return 0;
}

#endif

#if defined(__MINGW32__)
int inet_pton(int af, const char *src, void *dst) {
    struct sockaddr_storage ss;
    int size = sizeof(ss);
    char src_copy[max_addr_len + 1];

    ZeroMemory(&ss, sizeof(ss));
    /* stupid non-const API */
    strncpy(src_copy, src, max_addr_len + 1);
    src_copy[max_addr_len] = 0;

    if (WSAStringToAddress(src_copy, af, NULL, (struct sockaddr *)&ss, &size) == 0) {
        switch (af) {
            case AF_INET:
                *(struct in_addr *)dst = ((struct sockaddr_in *)&ss)->sin_addr;
                return 1;
            case AF_INET6:
                *(struct in6_addr *)dst = ((struct sockaddr_in6 *)&ss)->sin6_addr;
                return 1;
        }
    }
    return 0;
}

const char *inet_ntop(int af, const void *src, char *dst, socklen_t size) {
    struct sockaddr_storage ss;
    unsigned long s = size;

    ZeroMemory(&ss, sizeof(ss));
    ss.ss_family = af;

    switch (af) {
        case AF_INET:
            ((struct sockaddr_in *)&ss)->sin_addr = *(struct in_addr *)src;
            break;
        case AF_INET6:
            ((struct sockaddr_in6 *)&ss)->sin6_addr = *(struct in6_addr *)src;
            break;
        default:
            return NULL;
    }
    /* cannot direclty use &size because of strict aliasing rules */
    return (WSAAddressToString((struct sockaddr *)&ss, sizeof(ss), NULL, dst, &s) == 0) ? dst : NULL;
}
char *get_sock_error() {
    static char buf[1000];
    int e = WSAGetLastError();
    wchar_t *s = NULL;
    FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                   NULL, e,
                   MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                   (LPWSTR)&s, 0, NULL);
    sprintf(buf, "%d:%S", e, s);
    int len = strlen(buf);
    while (len > 0 && (buf[len - 1] == '\r' || buf[len - 1] == '\n')) {
        len--;
        buf[len] = 0;
    }
    LocalFree(s);
    return buf;
}
int get_sock_errno() {
    return WSAGetLastError();
}
#else
char *get_sock_error() {
    static char buf[1000];
    sprintf(buf, "%d:%s", errno, strerror(errno));
    return buf;
}
int get_sock_errno() {
    return errno;
}
#endif

u64_t get_current_time_us() {
    static u64_t value_fix = 0;
    static u64_t largest_value = 0;

    u64_t raw_value = (u64_t)(ev_time() * 1000 * 1000);

    u64_t fixed_value = raw_value + value_fix;

    if (fixed_value < largest_value) {
        value_fix += largest_value - fixed_value;
    } else {
        largest_value = fixed_value;
    }

    // printf("<%lld,%lld,%lld>\n",raw_value,value_fix,raw_value + value_fix);
    return raw_value + value_fix;  // new fixed value
}

u64_t get_current_time() {
    return get_current_time_us() / 1000;
}

u64_t pack_u64(u32_t a, u32_t b) {
    u64_t ret = a;
    ret <<= 32u;
    ret += b;
    return ret;
}
u32_t get_u64_h(u64_t a) {
    return a >> 32u;
}
u32_t get_u64_l(u64_t a) {
    return (a << 32u) >> 32u;
}

char *my_ntoa(u32_t ip) {
    in_addr a;
    a.s_addr = ip;
    return inet_ntoa(a);
}
/*
void init_random_number_fd()
{

        random_number_fd=open("/dev/urandom",O_RDONLY);

        if(random_number_fd==-1)
        {
                mylog(log_fatal,"error open /dev/urandom\n");
                myexit(-1);
        }
        setnonblocking(random_number_fd);
}*/

#if !defined(__MINGW32__)
struct random_fd_t {
    int random_number_fd;
    random_fd_t() {
        random_number_fd = open("/dev/urandom", O_RDONLY);

        if (random_number_fd == -1) {
            mylog(log_fatal, "error open /dev/urandom\n");
            myexit(-1);
        }
        setnonblocking(random_number_fd);
    }
    int get_fd() {
        return random_number_fd;
    }
} random_fd;
#else
struct my_random_t {
    std::random_device rd;
    std::mt19937 gen;
    std::uniform_int_distribution<u64_t> dis64;
    std::uniform_int_distribution<u32_t> dis32;

    std::uniform_int_distribution<unsigned char> dis8;

    my_random_t() {
        // std::mt19937 gen_tmp(rd());  //random device is broken on mingw
        timespec tmp_time;
        clock_gettime(CLOCK_MONOTONIC, &tmp_time);
        long long a = ((u64_t)tmp_time.tv_sec) * 1000000000llu + ((u64_t)tmp_time.tv_nsec);
        std::mt19937 gen_tmp(a);
        gen = gen_tmp;
        gen.discard(700000);  // magic
    }
    u64_t gen64() {
        return dis64(gen);
    }
    u32_t gen32() {
        return dis32(gen);
    }

    unsigned char gen8() {
        return dis8(gen);
    }
    /*int random_number_fd;
    random_fd_t()
    {
                    random_number_fd=open("/dev/urandom",O_RDONLY);
                    if(random_number_fd==-1)
                    {
                            mylog(log_fatal,"error open /dev/urandom\n");
                            myexit(-1);
                    }
                    setnonblocking(random_number_fd);
    }
    int get_fd()
    {
            return random_number_fd;
    }*/
} my_random;
#endif

u64_t get_true_random_number_64() {
#if !defined(__MINGW32__)
    u64_t ret;
    int size = read(random_fd.get_fd(), &ret, sizeof(ret));
    if (size != sizeof(ret)) {
        mylog(log_fatal, "get random number failed %d\n", size);
        myexit(-1);
    }
    return ret;
#else
    return my_random.gen64();  // fake random number
#endif
}
u32_t get_true_random_number() {
#if !defined(__MINGW32__)
    u32_t ret;
    int size = read(random_fd.get_fd(), &ret, sizeof(ret));
    if (size != sizeof(ret)) {
        mylog(log_fatal, "get random number failed %d\n", size);
        myexit(-1);
    }
    return ret;
#else
    return my_random.gen32();  // fake random number
#endif
}
u32_t get_true_random_number_nz()  // nz for non-zero
{
    u32_t ret = 0;
    while (ret == 0) {
        ret = get_true_random_number();
    }
    return ret;
}

inline int is_big_endian() {
    int i = 1;
    return !*((char *)&i);
}
u64_t ntoh64(u64_t a) {
#ifdef UDP2RAW_LITTLE_ENDIAN
    u32_t h = get_u64_h(a);
    u32_t l = get_u64_l(a);
    return pack_u64(ntohl(l), ntohl(h));
    // return bswap_64( a);
#else
    return a;
#endif
}
u64_t hton64(u64_t a) {
    return ntoh64(a);
}

void write_u16(char *p, u16_t w) {
    *(unsigned char *)(p + 1) = (w & 0xff);
    *(unsigned char *)(p + 0) = (w >> 8);
}
u16_t read_u16(char *p) {
    u16_t res;
    res = *(const unsigned char *)(p + 0);
    res = *(const unsigned char *)(p + 1) + (res << 8);
    return res;
}

void write_u32(char *p, u32_t l) {
    *(unsigned char *)(p + 3) = (unsigned char)((l >> 0) & 0xff);
    *(unsigned char *)(p + 2) = (unsigned char)((l >> 8) & 0xff);
    *(unsigned char *)(p + 1) = (unsigned char)((l >> 16) & 0xff);
    *(unsigned char *)(p + 0) = (unsigned char)((l >> 24) & 0xff);
}
u32_t read_u32(char *p) {
    u32_t res;
    res = *(const unsigned char *)(p + 0);
    res = *(const unsigned char *)(p + 1) + (res << 8);
    res = *(const unsigned char *)(p + 2) + (res << 8);
    res = *(const unsigned char *)(p + 3) + (res << 8);
    return res;
}

void write_u64(char *s, u64_t a) {
    assert(0 == 1);
}
u64_t read_u64(char *s) {
    assert(0 == 1);
    return 0;
}

void setnonblocking(int sock) {
#if !defined(__MINGW32__)
    int opts;
    opts = fcntl(sock, F_GETFL);

    if (opts < 0) {
        mylog(log_fatal, "fcntl(sock,GETFL)\n");
        // perror("fcntl(sock,GETFL)");
        myexit(1);
    }
    opts = opts | O_NONBLOCK;
    if (fcntl(sock, F_SETFL, opts) < 0) {
        mylog(log_fatal, "fcntl(sock,SETFL,opts)\n");
        // perror("fcntl(sock,SETFL,opts)");
        myexit(1);
    }
#else
    int iResult;
    u_long iMode = 1;
    iResult = ioctlsocket(sock, FIONBIO, &iMode);
    if (iResult != NO_ERROR)
        printf("ioctlsocket failed with error: %d\n", iResult);

#endif
}

/*
    Generic checksum calculation function
*/
unsigned short csum(const unsigned short *ptr, int nbytes) {  // works both for big and little endian
    long sum;
    unsigned short oddbyte;
    short answer;

    sum = 0;
    while (nbytes > 1) {
        sum += *ptr++;
        nbytes -= 2;
    }
    if (nbytes == 1) {
        oddbyte = 0;
        *((u_char *)&oddbyte) = *(u_char *)ptr;
        sum += oddbyte;
    }

    sum = (sum >> 16) + (sum & 0xffff);
    sum = sum + (sum >> 16);
    answer = (short)~sum;

    return (answer);
}

unsigned short csum_with_header(char *header, int hlen, const unsigned short *ptr, int nbytes) {  // works both for big and little endian

    long sum;
    unsigned short oddbyte;
    short answer;

    assert(hlen % 2 == 0);

    sum = 0;
    unsigned short *tmp = (unsigned short *)header;
    for (int i = 0; i < hlen / 2; i++) {
        sum += *tmp++;
    }

    while (nbytes > 1) {
        sum += *ptr++;
        nbytes -= 2;
    }
    if (nbytes == 1) {
        oddbyte = 0;
        *((u_char *)&oddbyte) = *(u_char *)ptr;
        sum += oddbyte;
    }

    sum = (sum >> 16) + (sum & 0xffff);
    sum = sum + (sum >> 16);
    answer = (short)~sum;

    return (answer);
}

int set_buf_size(int fd, int socket_buf_size) {
    if (force_socket_buf) {
        if (is_udp2raw_mp) {
            mylog(log_fatal, "force_socket_buf not supported in this verion\n");
            myexit(-1);
        }
        // assert(0==1);
#ifdef UDP2RAW_LINUX
        if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &socket_buf_size, sizeof(socket_buf_size)) < 0) {
            mylog(log_fatal, "SO_SNDBUFFORCE fail  socket_buf_size=%d  errno=%s\n", socket_buf_size, strerror(errno));
            myexit(1);
        }
        if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &socket_buf_size, sizeof(socket_buf_size)) < 0) {
            mylog(log_fatal, "SO_RCVBUFFORCE fail  socket_buf_size=%d  errno=%s\n", socket_buf_size, strerror(errno));
            myexit(1);
        }
#endif

    } else {
        if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &socket_buf_size, sizeof(socket_buf_size)) < 0) {
            mylog(log_fatal, "SO_SNDBUF fail  socket_buf_size=%d  errno=%s\n", socket_buf_size, get_sock_error());
            myexit(1);
        }
        if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &socket_buf_size, sizeof(socket_buf_size)) < 0) {
            mylog(log_fatal, "SO_RCVBUF fail  socket_buf_size=%d  errno=%s\n", socket_buf_size, get_sock_error());
            myexit(1);
        }
    }
    return 0;
}

int numbers_to_char(my_id_t id1, my_id_t id2, my_id_t id3, char *&data, int &len) {
    static char buf[buf_len];
    data = buf;
    my_id_t tmp = htonl(id1);
    memcpy(buf, &tmp, sizeof(tmp));

    tmp = htonl(id2);
    memcpy(buf + sizeof(tmp), &tmp, sizeof(tmp));

    tmp = htonl(id3);
    memcpy(buf + sizeof(tmp) * 2, &tmp, sizeof(tmp));

    len = sizeof(my_id_t) * 3;
    return 0;
}

int char_to_numbers(const char *data, int len, my_id_t &id1, my_id_t &id2, my_id_t &id3) {
    if (len < int(sizeof(my_id_t) * 3)) return -1;
    // id1=ntohl(  *((id_t*)(data+0)) );
    memcpy(&id1, data + 0, sizeof(id1));
    id1 = ntohl(id1);
    // id2=ntohl(  *((id_t*)(data+sizeof(id_t))) );
    memcpy(&id2, data + sizeof(my_id_t), sizeof(id2));
    id2 = ntohl(id2);
    // id3=ntohl(  *((id_t*)(data+sizeof(id_t)*2)) );
    memcpy(&id3, data + sizeof(my_id_t) * 2, sizeof(id3));
    id3 = ntohl(id3);
    return 0;
}
int hex_to_u32(const string &a, u32_t &output) {
    // string b="0x";
    // b+=a;
    if (sscanf(a.c_str(), "%x", &output) == 1) {
        // printf("%s %x\n",a.c_str(),output);
        return 0;
    }
    mylog(log_error, "<%s> doesnt contain a hex\n", a.c_str());
    return -1;
}
int hex_to_u32_with_endian(const string &a, u32_t &output) {
    // string b="0x";
    // b+=a;
    if (sscanf(a.c_str(), "%x", &output) == 1) {
        output = htonl(output);
        // printf("%s %x\n",a.c_str(),output);
        return 0;
    }
    mylog(log_error, "<%s> doesnt contain a hex\n", a.c_str());
    return -1;
}
bool larger_than_u32(u32_t a, u32_t b) {
    return ((i32_t(a - b)) > 0);
    /*
            u32_t smaller,bigger;
            smaller=min(a,b);//smaller in normal sense
            bigger=max(a,b);
            u32_t distance=min(bigger-smaller,smaller+(0xffffffff-bigger+1));
            if(distance==bigger-smaller)
            {
                    if(bigger==a)
                    {
                            return 1;
                    }
                    else
                    {
                            return 0;
                    }
            }
            else
            {
                    if(smaller==b)
                    {
                            return 0;
                    }
                    else
                    {
                            return 1;
                    }
            }
    */
}

bool larger_than_u16(uint16_t a, uint16_t b) {
    return ((i16_t(a - b)) > 0);
    /*
            uint16_t smaller,bigger;
            smaller=min(a,b);//smaller in normal sense
            bigger=max(a,b);
            uint16_t distance=min(bigger-smaller,smaller+(0xffff-bigger+1));
            if(distance==bigger-smaller)
            {
                    if(bigger==a)
                    {
                            return 1;
                    }
                    else
                    {
                            return 0;
                    }
            }
            else
            {
                    if(smaller==b)
                    {
                            return 0;
                    }
                    else
                    {
                            return 1;
                    }
            }*/
}

void myexit(int a) {
    if (enable_log_color)
        printf("%s\n", RESET);
#ifdef UDP2RAW_LINUX
    if (keep_thread_running) {
        if (pthread_cancel(keep_thread)) {
            mylog(log_warn, "pthread_cancel failed\n");
        } else {
            mylog(log_info, "pthread_cancel success\n");
        }
    }
    clear_iptables_rule();
#endif
    exit(a);
}

vector<string> string_to_vec(const char *s, const char *sp) {
    vector<string> res;
    string str = s;
    char *p = strtok((char *)str.c_str(), sp);
    while (p != NULL) {
        res.push_back(p);
        // printf ("%s\n",p);
        p = strtok(NULL, sp);
    }

    /* for(int i=0;i<(int)res.size();i++)
     {
             printf("<<%s>>\n",res[i].c_str());
     }*/
    return res;
}

vector<vector<string> > string_to_vec2(const char *s) {
    vector<vector<string> > res;
    vector<string> lines = string_to_vec(s, "\n");
    for (int i = 0; i < int(lines.size()); i++) {
        vector<string> tmp;
        tmp = string_to_vec(lines[i].c_str(), "\t ");
        res.push_back(tmp);
    }
    return res;
}
int read_file(const char *file, string &output) {
    const int max_len = 3 * 1024 * 1024;
    // static char buf[max_len+100];
    string buf0;
    buf0.reserve(max_len + 200);
    char *buf = (char *)buf0.c_str();
    buf[max_len] = 0;
    // buf[sizeof(buf)-1]=0;
    int fd = open(file, O_RDONLY);
    if (fd == -1) {
        mylog(log_error, "read_file %s fail\n", file);
        return -1;
    }
    int len = read(fd, buf, max_len);
    if (len == max_len) {
        buf[0] = 0;
        mylog(log_error, "%s too long,buf not large enough\n", file);
        return -2;
    } else if (len < 0) {
        buf[0] = 0;
        mylog(log_error, "%s read fail %d\n", file, len);
        return -3;
    } else {
        buf[len] = 0;
        output = buf;
    }
    return 0;
}
int run_command(string command0, char *&output, int flag) {
    if (is_udp2raw_mp) {
        mylog(log_fatal, "run_command not supported in this version\n");
        myexit(-1);
    }
#ifdef UDP2RAW_LINUX
    FILE *in;

    if ((flag & show_log) == 0) command0 += " 2>&1 ";

    const char *command = command0.c_str();

    int level = (flag & show_log) ? log_warn : log_debug;

    if (flag & show_command) {
        mylog(log_info, "run_command %s\n", command);
    } else {
        mylog(log_debug, "run_command %s\n", command);
    }
    static __thread char buf[1024 * 1024 + 100];
    buf[sizeof(buf) - 1] = 0;
    if (!(in = popen(command, "r"))) {
        mylog(level, "command %s popen failed,errno %s\n", command, strerror(errno));
        return -1;
    }

    int len = fread(buf, 1024 * 1024, 1, in);
    if (len == 1024 * 1024) {
        buf[0] = 0;
        mylog(level, "too long,buf not larger enough\n");
        return -2;
    } else {
        buf[len] = 0;
    }
    int ret;
    if ((ret = ferror(in))) {
        mylog(level, "command %s fread failed,ferror return value %d \n", command, ret);
        return -3;
    }
    // if(output!=0)
    output = buf;
    ret = pclose(in);

    int ret2 = WEXITSTATUS(ret);

    if (ret != 0 || ret2 != 0) {
        mylog(level, "commnad %s ,pclose returned %d ,WEXITSTATUS %d,errnor :%s \n", command, ret, ret2, strerror(errno));
        return -4;
    }

#endif
    return 0;
}
/*
int run_command_no_log(string command0,char * &output) {
    FILE *in;
    command0+=" 2>&1 ";
    const char * command=command0.c_str();
    mylog(log_debug,"run_command_no_log %s\n",command);
    static char buf[1024*1024+100];
    buf[sizeof(buf)-1]=0;
    if(!(in = popen(command, "r"))){
        mylog(log_debug,"command %s popen failed,errno %s\n",command,strerror(errno));
        return -1;
    }

    int len =fread(buf, 1024*1024, 1, in);
    if(len==1024*1024)
    {
        buf[0]=0;
        mylog(log_debug,"too long,buf not larger enough\n");
        return -2;
    }
    else
    {
        buf[len]=0;
    }
    int ret;
    if(( ret=ferror(in) ))
    {
        mylog(log_debug,"command %s fread failed,ferror return value %d \n",command,ret);
        return -3;
    }
    //if(output!=0)
    output=buf;
    ret= pclose(in);

    int ret2=WEXITSTATUS(ret);

    if(ret!=0||ret2!=0)
    {
        mylog(log_debug,"commnad %s ,pclose returned %d ,WEXITSTATUS %d,errnor :%s \n",command,ret,ret2,strerror(errno));
        return -4;
    }

    return 0;

}*/

// Remove preceding and trailing characters
string trim(const string &str, char c) {
    size_t first = str.find_first_not_of(c);
    if (string::npos == first) {
        return "";
    }
    size_t last = str.find_last_not_of(c);
    return str.substr(first, (last - first + 1));
}

vector<string> parse_conf_line(const string &s0) {
    string s = s0;
    s.reserve(s.length() + 200);
    char *buf = (char *)s.c_str();
    // char buf[s.length()+200];
    char *p = buf;
    int i = int(s.length()) - 1;
    int j;
    vector<string> res;
    // strcpy(buf,(char *)s.c_str());
    while (i >= 0) {
        if (buf[i] == ' ' || buf[i] == '\t')
            buf[i] = 0;
        else
            break;
        i--;
    }
    while (*p != 0) {
        if (*p == ' ' || *p == '\t') {
            p++;
        } else
            break;
    }
    int new_len = strlen(p);
    if (new_len == 0) return res;
    if (p[0] == '#') return res;
    if (p[0] != '-') {
        mylog(log_fatal, "line :<%s> not begin with '-' ", s.c_str());
        myexit(-1);
    }

    for (i = 0; i < new_len; i++) {
        if (p[i] == ' ' || p[i] == '\t') {
            break;
        }
    }
    if (i == new_len) {
        res.push_back(p);
        return res;
    }

    j = i;
    while (p[j] == ' ' || p[j] == '\t')
        j++;
    p[i] = 0;
    res.push_back(p);
    res.push_back(p + j);
    return res;
}

int create_fifo(char *file) {
#if !defined(__MINGW32__)
    if (mkfifo(file, 0666) != 0) {
        if (errno == EEXIST) {
            mylog(log_warn, "warning fifo file %s exist\n", file);
        } else {
            mylog(log_fatal, "create fifo file %s failed\n", file);
            myexit(-1);
        }
    }
    int fifo_fd = open(file, O_RDWR);
    if (fifo_fd < 0) {
        mylog(log_fatal, "create fifo file %s failed\n", file);
        myexit(-1);
    }
    struct stat st;
    if (fstat(fifo_fd, &st) != 0) {
        mylog(log_fatal, "fstat failed for fifo file %s\n", file);
        myexit(-1);
    }

    if (!S_ISFIFO(st.st_mode)) {
        mylog(log_fatal, "%s is not a fifo\n", file);
        myexit(-1);
    }

    setnonblocking(fifo_fd);
    return fifo_fd;
#else
    mylog(log_fatal, "--fifo not supported in this version\n");
    myexit(-1);
    return 0;
#endif
}

/*
void ip_port_t::from_u64(u64_t u64)
{
        ip=get_u64_h(u64);
        port=get_u64_l(u64);
}
u64_t ip_port_t::to_u64()
{
        return pack_u64(ip,port);
}
char * ip_port_t::to_s()
{
        static char res[40];
        sprintf(res,"%s:%d",my_ntoa(ip),port);
        return res;
}*/

void print_binary_chars(const char *a, int len) {
    for (int i = 0; i < len; i++) {
        unsigned char b = a[i];
        log_bare(log_debug, "<%02x>", (int)b);
    }
    log_bare(log_debug, "\n");
}

u32_t djb2(unsigned char *str, int len) {
    u32_t hash = 5381;
    int c;
    for (int i=0; i<len ;i++) {
        c = *(str++);
        hash = ((hash << 5) + hash) ^ c; /* (hash * 33) ^ c */
    }

    hash = htonl(hash);
    return hash;
}

u32_t sdbm(unsigned char *str, int len) {
    u32_t hash = 0;
    int c;
    for (int i=0; i<len ;i++) {
        c = *(str++);
        hash = c + (hash << 6) + (hash << 16) - hash;
    }
    // hash=htonl(hash);
    return hash;
}


================================================
FILE: common.h
================================================
/*
 * common.h
 *
 *  Created on: Jul 29, 2017
 *      Author: wangyu
 */

#ifndef UDP2RAW_COMMON_H_
#define UDP2RAW_COMMON_H_
#define __STDC_FORMAT_MACROS 1
#include <inttypes.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>

#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <stdlib.h>  //for exit(0);
#include <errno.h>   //For errno - the error number
#include <fcntl.h>
#include <sys/time.h>
#include <time.h>
#include <stdarg.h>
#include <assert.h>
#include <pthread.h>

#ifndef USE_LIBNET
#define NO_LIBNET
#endif

#if defined(UDP2RAW_MP)
const int is_udp2raw_mp = 1;
#if !defined(__CYGWIN__) && !defined(__MINGW32__)
#include <pcap.h>
#else
#include <pcap_wrapper.h>
#define NO_LIBNET
#endif

#ifndef NO_LIBNET
#include <libnet.h>
#endif

#else
#define UDP2RAW_LINUX
const int is_udp2raw_mp = 0;
//#include <linux/if_ether.h>
#include <linux/filter.h>
#include <linux/if_packet.h>
#include <sys/epoll.h>
//#include <sys/wait.h> //signal
#include <netinet/if_ether.h>
#include <net/if.h>
#include <sys/timerfd.h>

#endif

#if !defined(NO_LIBEV_EMBED)
#include <my_ev.h>
#else
#include "ev.h"
#endif

#if defined(__MINGW32__)
#include <winsock2.h>
#include <ws2ipdef.h>
typedef unsigned char u_int8_t;
typedef unsigned short u_int16_t;
typedef unsigned int u_int32_t;
typedef int socklen_t;
#else
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#endif

#include <unordered_map>
#include <fstream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <list>
using namespace std;

#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN ||             \
    defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ || \
    defined(__BIG_ENDIAN__) ||                                           \
    defined(__ARMEB__) ||                                                \
    defined(__THUMBEB__) ||                                              \
    defined(__AARCH64EB__) ||                                            \
    defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__)
#define UDP2RAW_BIG_ENDIAN 1
#endif

#if defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN ||             \
    defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || \
    defined(__LITTLE_ENDIAN__) ||                                           \
    defined(__ARMEL__) ||                                                   \
    defined(__THUMBEL__) ||                                                 \
    defined(__AARCH64EL__) ||                                               \
    defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__)
#define UDP2RAW_LITTLE_ENDIAN 1
#endif

#if defined(UDP2RAW_BIG_ENDIAN) && defined(UDP2RAW_LITTLE_ENDIAN)
#error "endian detection conflicts"
#endif

#if !defined(UDP2RAW_BIG_ENDIAN) && !defined(UDP2RAW_LITTLE_ENDIAN)
#error "endian detection failed"
#endif

#if defined(__MINGW32__)
int inet_pton(int af, const char *src, void *dst);
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
#define setsockopt(a, b, c, d, e) setsockopt(a, b, c, (const char *)(d), e)
#endif

char *get_sock_error();
int get_sock_errno();

#if defined(__MINGW32__)
typedef SOCKET my_fd_t;
inline int sock_close(my_fd_t fd) {
    return closesocket(fd);
}
#else
typedef int my_fd_t;
inline int sock_close(my_fd_t fd) {
    return close(fd);
}

#endif

typedef unsigned long long u64_t;  // this works on most platform,avoid using the PRId64
typedef long long i64_t;

typedef unsigned int u32_t;
typedef int i32_t;

typedef unsigned short u16_t;
typedef short i16_t;

typedef u32_t my_id_t;

typedef u64_t iv_t;

typedef u64_t padding_t;

typedef u64_t anti_replay_seq_t;

typedef u64_t my_time_t;

const int max_addr_len = 100;

extern int force_socket_buf;

extern int g_fix_gro;

/*
struct ip_port_t
{
        u32_t ip;
        int port;
        void from_u64(u64_t u64);
        u64_t to_u64();
        char * to_s();
};*/

typedef u64_t fd64_t;

u32_t djb2(unsigned char *str, int len);
u32_t sdbm(unsigned char *str, int len);

struct address_t  // TODO scope id
{
    struct hash_function {
        u32_t operator()(const address_t &key) const {
            return sdbm((unsigned char *)&key.inner, sizeof(key.inner));
        }
    };

    union storage_t  // sockaddr_storage is too huge, we dont use it.
    {
        sockaddr_in ipv4;
        sockaddr_in6 ipv6;
    };
    storage_t inner;

    address_t() {
        clear();
    }
    void clear() {
        memset(&inner, 0, sizeof(inner));
    }
    int from_ip_port(u32_t ip, int port) {
        clear();
        inner.ipv4.sin_family = AF_INET;
        inner.ipv4.sin_port = htons(port);
        inner.ipv4.sin_addr.s_addr = ip;
        return 0;
    }

    int from_ip_port_new(int type, void *ip, int port) {
        clear();
        if (type == AF_INET) {
            inner.ipv4.sin_family = AF_INET;
            inner.ipv4.sin_port = htons(port);
            inner.ipv4.sin_addr.s_addr = *((u32_t *)ip);
        } else if (type == AF_INET6) {
            inner.ipv6.sin6_family = AF_INET6;
            inner.ipv6.sin6_port = htons(port);
            inner.ipv6.sin6_addr = *((in6_addr *)ip);
        }
        return 0;
    }

    int from_str(char *str);

    int from_str_ip_only(char *str);

    int from_sockaddr(sockaddr *, socklen_t);

    char *get_str();
    void to_str(char *);

    inline u32_t get_type() {
        u32_t ret = ((sockaddr *)&inner)->sa_family;
        assert(ret == AF_INET || ret == AF_INET6);
        return ret;
    }

    inline u32_t get_len() {
        u32_t type = get_type();
        switch (type) {
            case AF_INET:
                return sizeof(sockaddr_in);
            case AF_INET6:
                return sizeof(sockaddr_in6);
            default:
                assert(0 == 1);
        }
        return -1;
    }

    inline u32_t get_port() {
        u32_t type = get_type();
        switch (type) {
            case AF_INET:
                return ntohs(inner.ipv4.sin_port);
            case AF_INET6:
                return ntohs(inner.ipv6.sin6_port);
            default:
                assert(0 == 1);
        }
        return -1;
    }

    inline void set_port(int port) {
        u32_t type = get_type();
        switch (type) {
            case AF_INET:
                inner.ipv4.sin_port = htons(port);
                break;
            case AF_INET6:
                inner.ipv6.sin6_port = htons(port);
                break;
            default:
                assert(0 == 1);
        }
        return;
    }

    bool operator==(const address_t &b) const {
        // return this->data==b.data;
        return memcmp(&this->inner, &b.inner, sizeof(this->inner)) == 0;
    }

    int new_connected_udp_fd();

    char *get_ip();
};

namespace std {
template <>
struct hash<address_t> {
    std::size_t operator()(const address_t &key) const {
        // return address_t::hash_function(k);
        return sdbm((unsigned char *)&key.inner, sizeof(key.inner));
    }
};
}  // namespace std

union my_ip_t  // just a simple version of address_t,stores ip only
{
    u32_t v4;
    in6_addr v6;

    bool equal(const my_ip_t &b) const;

    // int from_str(char * str);
    char *get_str1() const;
    char *get_str2() const;

    int from_address_t(address_t a);
};

struct not_copy_able_t {
    not_copy_able_t() {
    }
    not_copy_able_t(const not_copy_able_t &other) {
        assert(0 == 1);
    }
    const not_copy_able_t &operator=(const not_copy_able_t &other) {
        assert(0 == 1);
        return other;
    }
};

const int huge_data_len = 65535 + 100;  // a packet with link level header might be larger than 65535
const int huge_buf_len = huge_data_len + 100;

const int max_data_len = 1800;
const int buf_len = max_data_len + 400;

// const int max_address_len=512;

#ifdef UDP2RAW_MP
const int queue_len = 200;

struct queue_t {
    char data[queue_len][huge_buf_len];
    int data_len[queue_len];

    int head = 0;
    int tail = 0;
    void clear() {
        head = tail = 0;
    }
    int empty() {
        if (head == tail)
            return 1;
        else
            return 0;
    }
    int full() {
        if ((tail + 1) % queue_len == head)
            return 1;
        else
            return 0;
    }
    void peek_front(char *&p, int &len) {
        assert(!empty());
        p = data[head];
        len = data_len[head];
    }
    void pop_front() {
        assert(!empty());
        head++;
        head %= queue_len;
    }
    void push_back(char *p, int len) {
        assert(!full());
        memcpy(data[tail], p, len);
        data_len[tail] = len;
        tail++;
        tail %= queue_len;
    }
};

int init_ws();
#endif
u64_t get_current_time();
u64_t pack_u64(u32_t a, u32_t b);

u32_t get_u64_h(u64_t a);

u32_t get_u64_l(u64_t a);

char *my_ntoa(u32_t ip);

void init_random_number_fd();
u64_t get_true_random_number_64();
u32_t get_true_random_number();
u32_t get_true_random_number_nz();
u64_t ntoh64(u64_t a);
u64_t hton64(u64_t a);

void write_u16(char *, u16_t a);  // network order
u16_t read_u16(char *);
void write_u32(char *, u32_t a);  // network order
u32_t read_u32(char *);
void write_u64(char *, u64_t a);
u64_t read_u64(char *);

bool larger_than_u16(uint16_t a, uint16_t b);
bool larger_than_u32(u32_t a, u32_t b);
void setnonblocking(int sock);
int set_buf_size(int fd, int socket_buf_size);

void myexit(int a);

unsigned short csum(const unsigned short *ptr, int nbytes);
unsigned short csum_with_header(char *header, int hlen, const unsigned short *ptr, int nbytes);

int numbers_to_char(my_id_t id1, my_id_t id2, my_id_t id3, char *&data, int &len);
int char_to_numbers(const char *data, int len, my_id_t &id1, my_id_t &id2, my_id_t &id3);

const int show_none = 0;
const int show_command = 0x1;
const int show_log = 0x2;
const int show_all = show_command | show_log;

int run_command(string command, char *&output, int flag = show_all);
// int run_command_no_log(string command,char * &output);
int read_file(const char *file, string &output);

vector<string> string_to_vec(const char *s, const char *sp);
vector<vector<string> > string_to_vec2(const char *s);

string trim(const string &str, char c);

string trim_conf_line(const string &str);

vector<string> parse_conf_line(const string &s);

int hex_to_u32_with_endian(const string &a, u32_t &output);
int hex_to_u32(const string &a, u32_t &output);
// extern string iptables_pattern;

int create_fifo(char *file);

void print_binary_chars(const char *a, int len);

template <class key_t>
struct lru_collector_t : not_copy_able_t {
    // typedef void* key_t;
    //#define key_t void*
    struct lru_pair_t {
        key_t key;
        my_time_t ts;
    };

    unordered_map<key_t, typename list<lru_pair_t>::iterator> mp;

    list<lru_pair_t> q;
    int update(key_t key) {
        assert(mp.find(key) != mp.end());
        auto it = mp[key];
        q.erase(it);

        my_time_t value = get_current_time();
        if (!q.empty()) {
            assert(value >= q.front().ts);
        }
        lru_pair_t tmp;
        tmp.key = key;
        tmp.ts = value;
        q.push_front(tmp);
        mp[key] = q.begin();

        return 0;
    }
    int new_key(key_t key) {
        assert(mp.find(key) == mp.end());

        my_time_t value = get_current_time();
        if (!q.empty()) {
            assert(value >= q.front().ts);
        }
        lru_pair_t tmp;
        tmp.key = key;
        tmp.ts = value;
        q.push_front(tmp);
        mp[key] = q.begin();

        return 0;
    }
    int size() {
        return q.size();
    }
    int empty() {
        return q.empty();
    }
    void clear() {
        mp.clear();
        q.clear();
    }
    my_time_t ts_of(key_t key) {
        assert(mp.find(key) != mp.end());
        return mp[key]->ts;
    }

    my_time_t peek_back(key_t &key) {
        assert(!q.empty());
        auto it = q.end();
        it--;
        key = it->key;
        return it->ts;
    }
    void erase(key_t key) {
        assert(mp.find(key) != mp.end());
        q.erase(mp[key]);
        mp.erase(key);
    }
    /*
    void erase_back()
    {
            assert(!q.empty());
            auto it=q.end(); it--;
            key_t key=it->key;
            erase(key);
    }*/
};

#endif /* COMMON_H_ */


================================================
FILE: connection.cpp
================================================
/*
 * connection.cpp
 *
 *  Created on: Sep 23, 2017
 *      Author: root
 */

#include "connection.h"
#include "encrypt.h"
#include "fd_manager.h"

int disable_anti_replay = 0;  // if anti_replay windows is diabled

const int disable_conn_clear = 0;  // a raw connection is called conn.

conn_manager_t conn_manager;

anti_replay_seq_t anti_replay_t::get_new_seq_for_send() {
    return anti_replay_seq++;
}
anti_replay_t::anti_replay_t() {
    max_packet_received = 0;
    anti_replay_seq = get_true_random_number_64() / 10;  // random first seq
    // memset(window,0,sizeof(window)); //not necessary
}
void anti_replay_t::re_init() {
    max_packet_received = 0;
    // memset(window,0,sizeof(window));
}

int anti_replay_t::is_vaild(u64_t seq) {
    if (disable_anti_replay) return 1;
    // if(disabled) return 0;

    if (seq == max_packet_received)
        return 0;
    else if (seq > max_packet_received) {
        if (seq - max_packet_received >= anti_replay_window_size) {
            memset(window, 0, sizeof(window));
            window[seq % anti_replay_window_size] = 1;
        } else {
            for (u64_t i = max_packet_received + 1; i < seq; i++)
                window[i % anti_replay_window_size] = 0;
            window[seq % anti_replay_window_size] = 1;
        }
        max_packet_received = seq;
        return 1;
    } else if (seq < max_packet_received) {
        if (max_packet_received - seq >= anti_replay_window_size)
            return 0;
        else {
            if (window[seq % anti_replay_window_size] == 1)
                return 0;
            else {
                window[seq % anti_replay_window_size] = 1;
                return 1;
            }
        }
    }

    return 0;  // for complier check
}

void conn_info_t::recover(const conn_info_t &conn_info) {
    raw_info = conn_info.raw_info;

    raw_info.rst_received = 0;
    raw_info.disabled = 0;

    last_state_time = conn_info.last_state_time;
    last_hb_recv_time = conn_info.last_hb_recv_time;
    last_hb_sent_time = conn_info.last_hb_sent_time;
    my_id = conn_info.my_id;
    oppsite_id = conn_info.oppsite_id;
    blob->anti_replay.re_init();

    my_roller = 0;       // no need to set,but for easier debug,set it to zero
    oppsite_roller = 0;  // same as above
    last_oppsite_roller_time = 0;
}

void conn_info_t::re_init() {
    // send_packet_info.protocol=g_packet_info_send.protocol;
    if (program_mode == server_mode)
        state.server_current_state = server_idle;
    else
        state.client_current_state = client_idle;
    last_state_time = 0;
    oppsite_const_id = 0;

    timer_fd64 = 0;

    my_roller = 0;
    oppsite_roller = 0;
    last_oppsite_roller_time = 0;
}
conn_info_t::conn_info_t() {
    blob = 0;
    re_init();
}
void conn_info_t::prepare() {
    assert(blob == 0);
    blob = new blob_t;
    if (program_mode == server_mode) {
        blob->conv_manager.s.additional_clear_function = server_clear_function;
    } else {
        assert(program_mode == client_mode);
    }
}

conn_info_t::conn_info_t(const conn_info_t &b) {
    assert(0 == 1);
    // mylog(log_error,"called!!!!!!!!!!!!!\n");
}

conn_info_t &conn_info_t::operator=(const conn_info_t &b) {
    mylog(log_fatal, "not allowed\n");
    myexit(-1);
    return *this;
}
conn_info_t::~conn_info_t() {
    if (program_mode == server_mode) {
        if (state.server_current_state == server_ready) {
            assert(blob != 0);
            assert(oppsite_const_id != 0);
            // assert(conn_manager.const_id_mp.find(oppsite_const_id)!=conn_manager.const_id_mp.end()); // conn_manager 's deconstuction function  erases it
        } else {
            assert(blob == 0);
            assert(oppsite_const_id == 0);
        }
    }
    assert(timer_fd64 == 0);
    // if(oppsite_const_id!=0)     //do this at conn_manager 's deconstuction function
    // conn_manager.const_id_mp.erase(oppsite_const_id);
    if (blob != 0)
        delete blob;

    // send_packet_info.protocol=g_packet_info_send.protocol;
}

conn_manager_t::conn_manager_t() {
    ready_num = 0;
    mp.reserve(10007);
    // clear_it=mp.begin();
    // timer_fd_mp.reserve(10007);
    const_id_mp.reserve(10007);
    // udp_fd_mp.reserve(100007);
    last_clear_time = 0;
    // current_ready_ip=0;
    // current_ready_port=0;
}
int conn_manager_t::exist(address_t addr) {
    // u64_t u64=0;
    // u64=ip;
    // u64<<=32u;
    // u64|=port;
    if (mp.find(addr) != mp.end()) {
        return 1;
    }
    return 0;
}
/*
int insert(uint32_t ip,uint16_t port)
{
        uint64_t u64=0;
        u64=ip;
        u64<<=32u;
        u64|=port;
        mp[u64];
        return 0;
}*/
conn_info_t *&conn_manager_t::find_insert_p(address_t addr)  // be aware,the adress may change after rehash
{
    // u64_t u64=0;
    // u64=ip;
    // u64<<=32u;
    // u64|=port;
    unordered_map<address_t, conn_info_t *>::iterator it = mp.find(addr);
    if (it == mp.end()) {
        mp[addr] = new conn_info_t;
        // lru.new_key(addr);
    } else {
        // lru.update(addr);
    }
    return mp[addr];
}
conn_info_t &conn_manager_t::find_insert(address_t addr)  // be aware,the adress may change after rehash
{
    // u64_t u64=0;
    // u64=ip;
    // u64<<=32u;
    // u64|=port;
    unordered_map<address_t, conn_info_t *>::iterator it = mp.find(addr);
    if (it == mp.end()) {
        mp[addr] = new conn_info_t;
        // lru.new_key(addr);
    } else {
        // lru.update(addr);
    }
    return *mp[addr];
}
int conn_manager_t::erase(unordered_map<address_t, conn_info_t *>::iterator erase_it) {
    if (erase_it->second->state.server_current_state == server_ready) {
        ready_num--;
        assert(i32_t(ready_num) != -1);
        assert(erase_it->second != 0);

        assert(erase_it->second->timer_fd64 != 0);

        assert(fd_manager.exist(erase_it->second->timer_fd64));

        assert(erase_it->second->oppsite_const_id != 0);
        assert(const_id_mp.find(erase_it->second->oppsite_const_id) != const_id_mp.end());

        // assert(timer_fd_mp.find(erase_it->second->timer_fd)!=timer_fd_mp.end());

        const_id_mp.erase(erase_it->second->oppsite_const_id);

        fd_manager.fd64_close(erase_it->second->timer_fd64);

        erase_it->second->timer_fd64 = 0;
        // timer_fd_mp.erase(erase_it->second->timer_fd);
        // close(erase_it->second->timer_fd);// close will auto delte it from epoll
        delete (erase_it->second);
        mp.erase(erase_it->first);
    } else {
        assert(erase_it->second->blob == 0);
        assert(erase_it->second->timer_fd64 == 0);

        assert(erase_it->second->oppsite_const_id == 0);
        delete (erase_it->second);
        mp.erase(erase_it->first);
    }
    return 0;
}
int conn_manager_t::clear_inactive() {
    if (get_current_time() - last_clear_time > conn_clear_interval) {
        last_clear_time = get_current_time();
        return clear_inactive0();
    }
    return 0;
}
int conn_manager_t::clear_inactive0() {
    unordered_map<address_t, conn_info_t *>::iterator it;
    unordered_map<address_t, conn_info_t *>::iterator old_it;

    if (disable_conn_clear) return 0;

    // map<uint32_t,uint64_t>::iterator it;
    int cnt = 0;
    it = clear_it;
    int size = mp.size();
    int num_to_clean = size / conn_clear_ratio + conn_clear_min;  // clear 1/10 each time,to avoid latency glitch

    mylog(log_trace, "mp.size() %d\n", size);

    num_to_clean = min(num_to_clean, (int)mp.size());
    u64_t current_time = get_current_time();

    for (;;) {
        if (cnt >= num_to_clean) break;
        if (mp.begin() == mp.end()) break;

        if (it == mp.end()) {
            it = mp.begin();
        }

        if (it->second->state.server_current_state == server_ready && current_time - it->second->last_hb_recv_time <= server_conn_timeout) {
            it++;
        } else if (it->second->state.server_current_state != server_ready && current_time - it->second->last_state_time <= server_handshake_timeout) {
            it++;
        } else if (it->second->blob != 0 && it->second->blob->conv_manager.s.get_size() > 0) {
            assert(it->second->state.server_current_state == server_ready);
            it++;
        } else {
            mylog(log_info, "[%s:%d]inactive conn cleared \n", it->second->raw_info.recv_info.new_src_ip.get_str1(), it->second->raw_info.recv_info.src_port);
            old_it = it;
            it++;
            erase(old_it);
        }
        cnt++;
    }
    clear_it = it;

    return 0;
}

int send_bare(raw_info_t &raw_info, const char *data, int len)  // send function with encryption but no anti replay,this is used when client and server verifys each other
// you have to design the protocol carefully, so that you wont be affect by relay attack
{
    if (len < 0) {
        mylog(log_debug, "input_len <0\n");
        return -1;
    }
    packet_info_t &send_info = raw_info.send_info;
    packet_info_t &recv_info = raw_info.recv_info;

    char send_data_buf[buf_len];  // buf for send data and send hb
    char send_data_buf2[buf_len];

    // static send_bare[buf_len];
    iv_t iv = get_true_random_number_64();
    padding_t padding = get_true_random_number_64();

    memcpy(send_data_buf, &iv, sizeof(iv));
    memcpy(send_data_buf + sizeof(iv), &padding, sizeof(padding));

    send_data_buf[sizeof(iv) + sizeof(padding)] = 'b';
    memcpy(send_data_buf + sizeof(iv) + sizeof(padding) + 1, data, len);
    int new_len = len + sizeof(iv) + sizeof(padding) + 1;

    if (my_encrypt(send_data_buf, send_data_buf2, new_len) != 0) {
        return -1;
    }
    send_raw0(raw_info, send_data_buf2, new_len);
    return 0;
}
int reserved_parse_bare(const char *input, int input_len, char *&data, int &len)  // a sub function used in recv_bare
{
    static char recv_data_buf[buf_len];

    if (input_len < 0) {
        mylog(log_debug, "input_len <0\n");
        return -1;
    }
    if (my_decrypt(input, recv_data_buf, input_len) != 0) {
        mylog(log_debug, "decrypt_fail in recv bare\n");
        return -1;
    }
    if (recv_data_buf[sizeof(iv_t) + sizeof(padding_t)] != 'b') {
        mylog(log_debug, "not a bare packet\n");
        return -1;
    }
    len = input_len;
    data = recv_data_buf + sizeof(iv_t) + sizeof(padding_t) + 1;
    len -= sizeof(iv_t) + sizeof(padding_t) + 1;
    if (len < 0) {
        mylog(log_debug, "len <0\n");
        return -1;
    }
    return 0;
}
int recv_bare(raw_info_t &raw_info, char *&data, int &len)  // recv function with encryption but no anti replay,this is used when client and server verifys each other
// you have to design the protocol carefully, so that you wont be affect by relay attack
{
    packet_info_t &send_info = raw_info.send_info;
    packet_info_t &recv_info = raw_info.recv_info;

    if (recv_raw0(raw_info, data, len) < 0) {
        // printf("recv_raw_fail in recv bare\n");
        return -1;
    }

    if (len >= max_data_len + 1) {
        mylog(log_debug, "data_len=%d >= max_data_len+1,ignored", len);
        return -1;
    }

    mylog(log_trace, "data len=%d\n", len);
    if ((raw_mode == mode_faketcp && (recv_info.syn == 1 || recv_info.ack != 1))) {
        mylog(log_debug, "unexpect packet type recv_info.syn=%d recv_info.ack=%d \n", recv_info.syn, recv_info.ack);
        return -1;
    }
    return reserved_parse_bare(data, len, data, len);
}

int send_handshake(raw_info_t &raw_info, my_id_t id1, my_id_t id2, my_id_t id3)  // a warp for send_bare for sending handshake(this is not tcp handshake) easily
{
    packet_info_t &send_info = raw_info.send_info;
    packet_info_t &recv_info = raw_info.recv_info;

    char *data;
    int len;
    // len=sizeof(id_t)*3;
    if (numbers_to_char(id1, id2, id3, data, len) != 0) return -1;
    if (send_bare(raw_info, data, len) != 0) {
        mylog(log_warn, "send bare fail\n");
        return -1;
    }
    return 0;
}
/*
int recv_handshake(packet_info_t &info,id_t &id1,id_t &id2,id_t &id3)
{
        char * data;int len;
        if(recv_bare(info,data,len)!=0) return -1;

        if(char_to_numbers(data,len,id1,id2,id3)!=0) return -1;

        return 0;
}*/

int send_safer(conn_info_t &conn_info, char type, const char *data, int len)  // safer transfer function with anti-replay,when mutually verification is done.
{
    packet_info_t &send_info = conn_info.raw_info.send_info;
    packet_info_t &recv_info = conn_info.raw_info.recv_info;

    if (type != 'h' && type != 'd') {
        mylog(log_warn, "first byte is not h or d  ,%x\n", type);
        return -1;
    }

    char send_data_buf[buf_len];  // buf for send data and send hb
    char send_data_buf2[buf_len];

    my_id_t n_tmp_id = htonl(conn_info.my_id);

    memcpy(send_data_buf, &n_tmp_id, sizeof(n_tmp_id));

    n_tmp_id = htonl(conn_info.oppsite_id);

    memcpy(send_data_buf + sizeof(n_tmp_id), &n_tmp_id, sizeof(n_tmp_id));

    anti_replay_seq_t n_seq = hton64(conn_info.blob->anti_replay.get_new_seq_for_send());

    memcpy(send_data_buf + sizeof(n_tmp_id) * 2, &n_seq, sizeof(n_seq));

    send_data_buf[sizeof(n_tmp_id) * 2 + sizeof(n_seq)] = type;
    send_data_buf[sizeof(n_tmp_id) * 2 + sizeof(n_seq) + 1] = conn_info.my_roller;

    memcpy(send_data_buf + 2 + sizeof(n_tmp_id) * 2 + sizeof(n_seq), data, len);  // data;

    int new_len = len + sizeof(n_seq) + sizeof(n_tmp_id) * 2 + 2;

    if (g_fix_gro == 0) {
        if (my_encrypt(send_data_buf, send_data_buf2, new_len) != 0) {
            return -1;
        }
    } else {
        if (my_encrypt(send_data_buf, send_data_buf2 + 2, new_len) != 0) {
            return -1;
        }
        write_u16(send_data_buf2, new_len);
        new_len += 2;
        if (cipher_mode == cipher_xor) {
            send_data_buf2[0] ^= gro_xor[0];
            send_data_buf2[1] ^= gro_xor[1];
        } else if (cipher_mode == cipher_aes128cbc || cipher_mode == cipher_aes128cfb) {
            aes_ecb_encrypt1(send_data_buf2);
        }
    }

    if (send_raw0(conn_info.raw_info, send_data_buf2, new_len) != 0) return -1;

    if (after_send_raw0(conn_info.raw_info) != 0) return -1;

    return 0;
}
int send_data_safer(conn_info_t &conn_info, const char *data, int len, u32_t conv_num)  // a wrap for  send_safer for transfer data.
{
    packet_info_t &send_info = conn_info.raw_info.send_info;
    packet_info_t &recv_info = conn_info.raw_info.recv_info;

    char send_data_buf[buf_len];
    // send_data_buf[0]='d';
    u32_t n_conv_num = htonl(conv_num);
    memcpy(send_data_buf, &n_conv_num, sizeof(n_conv_num));

    memcpy(send_data_buf + sizeof(n_conv_num), data, len);
    int new_len = len + sizeof(n_conv_num);
    send_safer(conn_info, 'd', send_data_buf, new_len);
    return 0;
}
int reserved_parse_safer(conn_info_t &conn_info, const char *input, int input_len, char &type, char *&data, int &len)  // subfunction for recv_safer,allow overlap
{
    static char recv_data_buf[buf_len];

    // char *recv_data_buf=recv_data_buf0; //fix strict alias warning
    if (my_decrypt(input, recv_data_buf, input_len) != 0) {
        // printf("decrypt fail\n");
        return -1;
    }

    // char *a=recv_data_buf;
    // id_t h_oppiste_id= ntohl (  *((id_t * )(recv_data_buf)) );
    my_id_t h_oppsite_id;
    memcpy(&h_oppsite_id, recv_data_buf, sizeof(h_oppsite_id));
    h_oppsite_id = ntohl(h_oppsite_id);

    // id_t h_my_id= ntohl (  *((id_t * )(recv_data_buf+sizeof(id_t)))    );
    my_id_t h_my_id;
    memcpy(&h_my_id, recv_data_buf + sizeof(my_id_t), sizeof(h_my_id));
    h_my_id = ntohl(h_my_id);

    // anti_replay_seq_t h_seq= ntoh64 (  *((anti_replay_seq_t * )(recv_data_buf  +sizeof(id_t) *2 ))   );
    anti_replay_seq_t h_seq;
    memcpy(&h_seq, recv_data_buf + sizeof(my_id_t) * 2, sizeof(h_seq));
    h_seq = ntoh64(h_seq);

    if (h_oppsite_id != conn_info.oppsite_id || h_my_id != conn_info.my_id) {
        mylog(log_debug, "id and oppsite_id verification failed %x %x %x %x \n", h_oppsite_id, conn_info.oppsite_id, h_my_id, conn_info.my_id);
        return -1;
    }

    if (conn_info.blob->anti_replay.is_vaild(h_seq) != 1) {
        mylog(log_debug, "dropped replay packet\n");
        return -1;
    }

    // printf("recv _len %d\n ",recv_len);
    data = recv_data_buf + sizeof(anti_replay_seq_t) + sizeof(my_id_t) * 2;
    len = input_len - (sizeof(anti_replay_seq_t) + sizeof(my_id_t) * 2);

    if (data[0] != 'h' && data[0] != 'd') {
        mylog(log_debug, "first byte is not h or d  ,%x\n", data[0]);
        return -1;
    }

    uint8_t roller = data[1];

    type = data[0];
    data += 2;
    len -= 2;

    if (len < 0) {
        mylog(log_debug, "len <0 ,%d\n", len);
        return -1;
    }

    if (roller != conn_info.oppsite_roller) {
        conn_info.oppsite_roller = roller;
        conn_info.last_oppsite_roller_time = get_current_time();
    }
    if (hb_mode == 0)
        conn_info.my_roller++;  // increase on a successful recv
    else if (hb_mode == 1) {
        if (type == 'h')
            conn_info.my_roller++;
    } else {
        mylog(log_fatal, "unknow hb_mode\n");
        myexit(-1);
    }

    if (after_recv_raw0(conn_info.raw_info) != 0) return -1;  // TODO might need to move this function to somewhere else after --fix-gro is introduced

    return 0;
}
int recv_safer_notused(conn_info_t &conn_info, char &type, char *&data, int &len)  /// safer transfer function with anti-replay,when mutually verification is done.
{
    packet_info_t &send_info = conn_info.raw_info.send_info;
    packet_info_t &recv_info = conn_info.raw_info.recv_info;

    char *recv_data;
    int recv_len;
    // static char recv_data_buf[buf_len];

    if (recv_raw0(conn_info.raw_info, recv_data, recv_len) != 0) return -1;

    return reserved_parse_safer(conn_info, recv_data, recv_len, type, data, len);
}

int recv_safer_multi(conn_info_t &conn_info, vector<char> &type_arr, vector<string> &data_arr)  /// safer transfer function with anti-replay,when mutually verification is done.
{
    packet_info_t &send_info = conn_info.raw_info.send_info;
    packet_info_t &recv_info = conn_info.raw_info.recv_info;

    char *recv_data;
    int recv_len;
    assert(type_arr.empty());
    assert(data_arr.empty());

    if (recv_raw0(conn_info.raw_info, recv_data, recv_len) != 0) return -1;

    char type;
    char *data;
    int len;

    if (g_fix_gro == 0) {
        int ret = reserved_parse_safer(conn_info, recv_data, recv_len, type, data, len);
        if (ret == 0) {
            type_arr.push_back(type);
            data_arr.emplace_back(data, data + len);
            // std::copy(data,data+len,data_arr[0]);
        }
        return 0;
    } else {
        char *ori_recv_data = recv_data;
        int ori_recv_len = recv_len;
        // mylog(log_debug,"recv_len:%d\n",recv_len);
        int cnt = 0;
        while (recv_len >= 16) {
            cnt++;
            int single_len_no_xor;
            single_len_no_xor = read_u16(recv_data);
            int single_len;
            if (cipher_mode == cipher_xor) {
                recv_data[0] ^= gro_xor[0];
                recv_data[1] ^= gro_xor[1];
            } else if (cipher_mode == cipher_aes128cbc || cipher_mode == cipher_aes128cfb) {
                aes_ecb_decrypt1(recv_data);
            }
            single_len = read_u16(recv_data);
            recv_len -= 2;
            recv_data += 2;
            if (single_len > recv_len) {
                mylog(log_debug, "illegal single_len %d(%d), recv_len %d left,dropped\n", single_len, single_len_no_xor, recv_len);
                break;
            }
            if (single_len > max_data_len) {
                mylog(log_warn, "single_len %d(%d) > %d, maybe you need to turn down mtu at upper level\n", single_len, single_len_no_xor, max_data_len);
                break;
            }

            int ret = reserved_parse_safer(conn_info, recv_data, single_len, type, data, len);

            if (ret != 0) {
                mylog(log_debug, "parse failed, offset= %d,single_len=%d(%d)\n", (int)(recv_data - ori_recv_data), single_len, single_len_no_xor);
            } else {
                type_arr.push_back(type);
                data_arr.emplace_back(data, data + len);
                // std::copy(data,data+len,data_arr[data_arr.size()-1]);
            }
            recv_data += single_len;
            recv_len -= single_len;
        }
        if (cnt > 1) {
            mylog(log_debug, "got a suspected gro packet, %d packets recovered, recv_len=%d, loop_cnt=%d\n", (int)data_arr.size(), ori_recv_len, cnt);
        }
        return 0;
    }
}

void server_clear_function(u64_t u64)  // used in conv_manager in server mode.for server we have to use one udp fd for one conv(udp connection),
// so we have to close the fd when conv expires
{
    // int fd=int(u64);
    //	int ret;
    // assert(fd!=0);
    /*
    epoll_event ev;

    ev.events = EPOLLIN;
    ev.data.u64 = u64;

    ret = epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &ev);
    if (ret!=0)
    {
            mylog(log_fatal,"fd:%d epoll delete failed!!!!\n",fd);
            myexit(-1);   //this shouldnt happen
    }*/
    // no need

    /*ret= close(fd);  //closed fd should be auto removed from epoll

    if (ret!=0)
    {
            mylog(log_fatal,"close fd %d failed !!!!\n",fd);
            myexit(-1);  //this shouldnt happen
    }*/
    // mylog(log_fatal,"size:%d !!!!\n",conn_manager.udp_fd_mp.size());
    fd64_t fd64 = u64;
    assert(fd_manager.exist(fd64));
    fd_manager.fd64_close(fd64);

    // assert(conn_manager.udp_fd_mp.find(fd)!=conn_manager.udp_fd_mp.end());
    // conn_manager.udp_fd_mp.erase(fd);
}


================================================
FILE: connection.h
================================================
/*
 * connection.h
 *
 *  Created on: Sep 23, 2017
 *      Author: root
 */

#ifndef CONNECTION_H_
#define CONNECTION_H_

extern int disable_anti_replay;

#include "connection.h"
#include "common.h"
#include "log.h"
#include "network.h"
#include "misc.h"

const int disable_conv_clear = 0;  // a udp connection in the multiplexer is called conversation in this program,conv for short.

struct anti_replay_t  // its for anti replay attack,similar to openvpn/ipsec 's anti replay window
{
    u64_t max_packet_received;
    char window[anti_replay_window_size];
    anti_replay_seq_t anti_replay_seq;
    anti_replay_seq_t get_new_seq_for_send();
    anti_replay_t();
    void re_init();

    int is_vaild(u64_t seq);
};  // anti_replay;

void server_clear_function(u64_t u64);

#include <type_traits>

template <class T>
struct conv_manager_t  // manage the udp connections
{
    // typedef hash_map map;
    unordered_map<T, u32_t> data_to_conv;  // conv and u64 are both supposed to be uniq
    unordered_map<u32_t, T> conv_to_data;

    lru_collector_t<u32_t> lru;
    // unordered_map<u32_t,u64_t> conv_last_active_time;

    // unordered_map<u32_t,u64_t>::iterator clear_it;

    void (*additional_clear_function)(T data) = 0;

    long long last_clear_time;

    conv_manager_t() {
        // clear_it=conv_last_active_time.begin();
        long long last_clear_time = 0;
        additional_clear_function = 0;
    }
    ~conv_manager_t() {
        clear();
    }
    int get_size() {
        return conv_to_data.size();
    }
    void reserve() {
        data_to_conv.reserve(10007);
        conv_to_data.reserve(10007);
        // conv_last_active_time.reserve(10007);

        lru.mp.reserve(10007);
    }
    void clear() {
        if (disable_conv_clear) return;

        if (additional_clear_function != 0) {
            for (auto it = conv_to_data.begin(); it != conv_to_data.end(); it++) {
                // int fd=int((it->second<<32u)>>32u);
                additional_clear_function(it->second);
            }
        }
        data_to_conv.clear();
        conv_to_data.clear();

        lru.clear();
        // conv_last_active_time.clear();

        // clear_it=conv_last_active_time.begin();
    }
    u32_t get_new_conv() {
        u32_t conv = get_true_random_number_nz();
        while (conv_to_data.find(conv) != conv_to_data.end()) {
            conv = get_true_random_number_nz();
        }
        return conv;
    }
    int is_conv_used(u32_t conv) {
        return conv_to_data.find(conv) != conv_to_data.end();
    }
    int is_data_used(T data) {
        return data_to_conv.find(data) != data_to_conv.end();
    }
    u32_t find_conv_by_data(T data) {
        return data_to_conv[data];
    }
    T find_data_by_conv(u32_t conv) {
        return conv_to_data[conv];
    }
    int update_active_time(u32_t conv) {
        // return conv_last_active_time[conv]=get_current_time();
        lru.update(conv);
        return 0;
    }
    int insert_conv(u32_t conv, T data) {
        data_to_conv[data] = conv;
        conv_to_data[conv] = data;
        // conv_last_active_time[conv]=get_current_time();
        lru.new_key(conv);
        return 0;
    }
    int erase_conv(u32_t conv) {
        if (disable_conv_clear) return 0;
        T data = conv_to_data[conv];
        if (additional_clear_function != 0) {
            additional_clear_function(data);
        }
        conv_to_data.erase(conv);
        data_to_conv.erase(data);
        // conv_last_active_time.erase(conv);
        lru.erase(conv);
        return 0;
    }
    int clear_inactive(char *info = 0) {
        if (get_current_time() - last_clear_time > conv_clear_interval) {
            last_clear_time = get_current_time();
            return clear_inactive0(info);
        }
        return 0;
    }
    int clear_inactive0(char *info) {
        if (disable_conv_clear) return 0;

        unordered_map<u32_t, u64_t>::iterator it;
        unordered_map<u32_t, u64_t>::iterator old_it;

        // map<uint32_t,uint64_t>::iterator it;
        int cnt = 0;
        // it=clear_it;
        int size = lru.size();
        int num_to_clean = size / conv_clear_ratio + conv_clear_min;  // clear 1/10 each time,to avoid latency glitch

        num_to_clean = min(num_to_clean, size);

        my_time_t current_time = get_current_time();
        for (;;) {
            if (cnt >= num_to_clean) break;
            if (lru.empty()) break;

            u32_t conv;
            my_time_t ts = lru.peek_back(conv);

            if (current_time - ts < conv_timeout) break;

            erase_conv(conv);
            if (info == 0) {
                mylog(log_info, "conv %x cleared\n", conv);
            } else {
                mylog(log_info, "[%s]conv %x cleared\n", info, conv);
            }
            cnt++;
        }
        return 0;
    }

    /*
conv_manager_t();
~conv_manager_t();
int get_size();
void reserve();
void clear();
u32_t get_new_conv();
int is_conv_used(u32_t conv);
int is_u64_used(T u64);
u32_t find_conv_by_u64(T u64);
T find_u64_by_conv(u32_t conv);
int update_active_time(u32_t conv);
int insert_conv(u32_t conv,T u64);
int erase_conv(u32_t conv);
int clear_inactive(char * ip_port=0);
int clear_inactive0(char * ip_port);*/
};  // g_conv_manager;

struct blob_t : not_copy_able_t  // used in conn_info_t.
{
    union tmp_union_t  // conv_manager_t is here to avoid copying when a connection is recovered
    {
        conv_manager_t<address_t> c;
        conv_manager_t<u64_t> s;
        // avoid templates here and there, avoid pointer and type cast
        tmp_union_t() {
            if (program_mode == client_mode) {
                new (&c) conv_manager_t<address_t>();
            } else {
                assert(program_mode == server_mode);
                new (&s) conv_manager_t<u64_t>();
            }
        }
        ~tmp_union_t() {
            if (program_mode == client_mode) {
                c.~conv_manager_t<address_t>();
            } else {
                assert(program_mode == server_mode);
                s.~conv_manager_t<u64_t>();
            }
        }
    } conv_manager;

    anti_replay_t anti_replay;  // anti_replay_t is here bc its huge,its allocation is delayed.
};
struct conn_info_t  // stores info for a raw connection.for client ,there is only one connection,for server there can be thousand of connection since server can
// handle multiple clients
{
    current_state_t state;

    raw_info_t raw_info;
    u64_t last_state_time;
    u64_t last_hb_sent_time;  // client re-use this for retry
    u64_t last_hb_recv_time;
    // long long last_resent_time;

    my_id_t my_id;
    my_id_t oppsite_id;

    fd64_t timer_fd64;
    fd64_t udp_fd64;

    my_id_t oppsite_const_id;

    blob_t *blob;

    uint8_t my_roller;
    uint8_t oppsite_roller;
    u64_t last_oppsite_roller_time;

    //	ip_port_t ip_port;

    /*
            const uint32_t &ip=raw_info.recv_info.src_ip;
            const uint16_t &port=raw_info.recv_info.src_port;

    */
    void recover(const conn_info_t &conn_info);
    void re_init();
    conn_info_t();
    void prepare();
    conn_info_t(const conn_info_t &b);
    conn_info_t &operator=(const conn_info_t &b);
    ~conn_info_t();
};  // g_conn_info;

struct conn_manager_t  // manager for connections. for client,we dont need conn_manager since there is only one connection.for server we use one conn_manager for all connections
{
    u32_t ready_num;

    // unordered_map<int,conn_info_t *> udp_fd_mp;  //a bit dirty to used pointer,but can void unordered_map search
    // unordered_map<int,conn_info_t *> timer_fd_mp;//we can use pointer here since unordered_map.rehash() uses shallow copy

    unordered_map<my_id_t, conn_info_t *> const_id_mp;

    unordered_map<address_t, conn_info_t *> mp;  // put it at end so that it de-consturcts first

    // lru_collector_t<address_t> lru;

    unordered_map<address_t, conn_info_t *>::iterator clear_it;

    long long last_clear_time;

    conn_manager_t();
    int exist(address_t addr);
    /*
    int insert(uint32_t ip,uint16_t port)
    {
            uint64_t u64=0;
            u64=ip;
            u64<<=32u;
            u64|=port;
            mp[u64];
            return 0;
    }*/
    conn_info_t *&find_insert_p(address_t addr);  // be aware,the adress may change after rehash //not true?
    conn_info_t &find_insert(address_t addr);     // be aware,the adress may change after rehash

    int erase(unordered_map<address_t, conn_info_t *>::iterator erase_it);
    int clear_inactive();
    int clear_inactive0();
};

extern conn_manager_t conn_manager;

void server_clear_function(u64_t u64);

int send_bare(raw_info_t &raw_info, const char *data, int len);  // send function with encryption but no anti replay,this is used when client and server verifys each other
// you have to design the protocol carefully, so that you wont be affect by relay attack
// int reserved_parse_bare(const char *input,int input_len,char* & data,int & len); // a sub function used in recv_bare
int recv_bare(raw_info_t &raw_info, char *&data, int &len);  // recv function with encryption but no anti replay,this is used when client and server verifys each other
// you have to design the protocol carefully, so that you wont be affect by relay attack
int send_handshake(raw_info_t &raw_info, my_id_t id1, my_id_t id2, my_id_t id3);         // a warp for send_bare for sending handshake(this is not tcp handshake) easily
int send_safer(conn_info_t &conn_info, char type, const char *data, int len);            // safer transfer function with anti-replay,when mutually verification is done.
int send_data_safer(conn_info_t &conn_info, const char *data, int len, u32_t conv_num);  // a wrap for  send_safer for transfer data.
// int reserved_parse_safer(conn_info_t &conn_info,const char * input,int input_len,char &type,char* &data,int &len);//subfunction for recv_safer,allow overlap

// int recv_safer(conn_info_t &conn_info,char &type,char* &data,int &len);///safer transfer function with anti-replay,when mutually verification is done.

int recv_safer_multi(conn_info_t &conn_info, vector<char> &type_arr, vector<string> &data_arr);  // new api for handle gro
#endif                                                                                           /* CONNECTION_H_ */


================================================
FILE: doc/README.zh-cn.md
================================================
# Udp2raw-tunnel 
![image2](/images/image0.PNG)
udp2raw tunnel,通过raw socket给UDP包加上TCP或ICMP header,进而绕过UDP屏蔽或QoS,或在UDP不稳定的环境下提升稳定性。可以有效防止在使用kcptun或者finalspeed的情况下udp端口被运营商限速。

支持心跳保活、自动重连,重连后会恢复上次连接,在底层掉线的情况下可以保持上层不掉线。同时有加密、防重放攻击、信道复用的功能。

[English](/README.md)

[udp2raw+kcptun step_by_step教程](kcptun_step_by_step.md)

[udp2raw+finalspeed step_by_step教程](finalspeed_step_by_step.md)

[udp2raw wiki](https://github.com/wangyu-/udp2raw-tunnel/wiki)

**提示:**

udp2raw不是加速器,只是一个帮助你绕过UDP限制的工具。如果你需要UDP“加速器” (改善UDP丢包),请看UDPspeeder。

UDPspeeder的repo:

https://github.com/wangyu-/UDPspeeder
# 支持的平台
Linux主机,有root权限或cap_net_raw capability.。可以是PC、android手机/平板、openwrt路由器、树莓派。主机上最好安装了iptables命令(apt/yum很容易安装)。

Release中提供了`amd64`、`x86`、`arm`、`mips_be`、`mips_le`的预编译binary.

##### 对于windows和mac用户:

可以用[这个repo](https://github.com/wangyu-/udp2raw-multiplatform)里的udp2raw。

##### 对于ios和游戏主机用户:

可以把udp2raw运行在局域网的其他机器/虚拟机上。最好的办法是买个能刷OpenWrt/LEDE/梅林的路由器,把udp2raw运行在路由器上。

# 功能特性
### 把udp流量伪装成tcp /icmp
用raw socket给udp包加上tcp/icmp包头,可以突破udp流量限制或Udp QOS。或者在udp nat有问题的环境下,提升稳定性。  另外也支持用raw 发udp包,这样流量不会被伪装,只会被加密。

### 模拟TCP3次握手
模拟TCP3次握手,模拟seq ack过程。另外还模拟了一些tcp option:MSS,sackOk,TS,TS_ack,wscale,用来使流量看起来更像是由普通的linux tcp协议栈发送的。

### 心跳保活、自动重连,连接恢复
心跳保活、自动重连,udp2raw重连可以恢复上次的连接,重连后上层连接继续有效,底层掉线上层不掉线。有效解决上层连接断开的问题。 (功能借鉴自[kcptun-raw](https://github.com/Chion82/kcptun-raw))(**就算你拔掉网线重插,或者重新拨号获得新ip,上层应用也不会断线**)

### 加密、防重放攻击
用aes128cbc加密(或更弱的xor),hmac-sha1(或更弱的md5/crc32/simple)做数据完整校验。用类似ipsec/openvpn的replay window机制来防止重放攻击。

[Notes on encryption](https://github.com/wangyu-/udp2raw-tunnel/wiki/Notes-on-encryption)

### 其他特性
信道复用,client的udp端支持多个连接。

server支持多个client,也能正确处理多个连接的重连和连接恢复。

NAT 穿透 ,tcp icmp udp模式都支持nat穿透。

支持Openvz,配合finalspeed使用,可以在openvz上用tcp模式的finalspeed.

支持Openwrt,没有编译依赖,容易编译到任何平台上。

### 关键词
突破udp qos,突破udp屏蔽,openvpn tcp over tcp problem,openvpn over icmp,udp to icmp tunnel,udp to tcp tunnel,udp via icmp,udp via tcp

# 简明操作说明

### 安装
下载编译好的二进制文件,解压到任意目录。

https://github.com/wangyu-/udp2raw-tunnel/releases

### 运行
假设你有一个server,ip为44.55.66.77,有一个服务监听在udp 7777端口。 假设你本地的主机到44.55.66.77的UDP流量被屏蔽了,或者被qos了

```
在server端运行:
./udp2raw_amd64 -s -l0.0.0.0:4096  -r127.0.0.1:7777   -k "passwd" --raw-mode faketcp   --cipher-mode xor  -a

在client端运行:
./udp2raw_amd64 -c -l0.0.0.0:3333  -r44.55.66.77:4096 -k "passwd" --raw-mode faketcp   --cipher-mode xor  -a
```
(以上例子需要用root账号运行。 用非root运行udp2raw需要一些额外的步骤,具体方法请看 [这个](https://github.com/wangyu-/udp2raw-tunnel/wiki/run-udp2raw-as-non-root) 链接。用非root运行更安全)

###### Server端输出:
![](/images/output_server.PNG)
###### Client端输出:
![](/images/output_client.PNG)

现在client和server之间建立起了,tunnel。想要在本地连接44.55.66.77:7777,只需要连接 127.0.0.1:3333。来回的所有的udp流量会被经过tunneling发送。在外界看起来是tcp流量,不会有udp流量暴露到公网。

### MTU设置(重要)

不论你用udp2raw来加速kcptun还是vpn,为了稳定使用,都需要设置合理的MTU(在kcptun/vpn里设置,而不是在udp2raw里),建议把MTU设置成1200。client和server端都要设置。

### 提醒
`--cipher-mode xor`表示仅使用简单的XOR加密,这样可以节省CPU占用,以免CPU成为速度瓶颈。如果你需要更强的加密,可以去掉此选项,使用默认的AES加密。加密相关的选项见后文的`--cipher-mode`和`--auth-mode`。

如果要在anroid上运行,请看[Android简明教程](/doc/android_guide.md)

`-a`选项会自动添加一条/几条iptables规则,udp2raw必须和相应的iptables规则配合才能稳定工作,一定要注意不要忘了`-a`(这是个常见错误)。 如果你不想让udp2raw自动添加iptables规则,可以自己手动添加相应的iptables规则(看一下`-g`选项),然后以不带`-a`的方式运行udp2raw。

# 进阶操作说明

### 命令选项
```
udp2raw-tunnel
git version:4623f878e0    build date:Nov  3 2024 23:15:46
repository: https://github.com/wangyu-/udp2raw-tunnel

usage:
    run as client : ./this_program -c -l local_listen_ip:local_port -r server_address:server_port  [options]
    run as server : ./this_program -s -l server_listen_ip:server_port -r remote_address:remote_port  [options]

common options,these options must be same on both side:
    --raw-mode            <string>        available values:faketcp(default),udp,icmp and easy-faketcp
    -k,--key              <string>        password to gen symetric key,default:"secret key"
    --cipher-mode         <string>        available values:aes128cfb,aes128cbc(default),xor,none
    --auth-mode           <string>        available values:hmac_sha1,md5(default),crc32,simple,none
    -a,--auto-rule                        auto add (and delete) iptables rule
    -g,--gen-rule                         generate iptables rule then exit,so that you can copy and
                                          add it manually.overrides -a
    --disable-anti-replay                 disable anti-replay,not suggested
    --fix-gro                             try to fix huge packet caused by GRO. this option is at an early stage.
                                          make sure client and server are at same version.
client options:
    --source-ip           <ip>            force source-ip for raw socket
    --source-port         <port>          force source-port for raw socket,tcp/udp only
                                          this option disables port changing while re-connecting
other options:
    --conf-file           <string>        read options from a configuration file instead of command line.
                                          check example.conf in repo for format
    --fifo                <string>        use a fifo(named pipe) for sending commands to the running program,
                                          check readme.md in repository for supported commands.
    --log-level           <number>        0:never    1:fatal   2:error   3:warn
                                          4:info (default)     5:debug   6:trace
    --log-position                        enable file name,function name,line number in log
    --disable-color                       disable log color
    --disable-bpf                         disable the kernel space filter,most time its not necessary
                                          unless you suspect there is a bug
    --dev                 <string>        bind raw socket to a device, not necessary but improves performance
    --sock-buf            <number>        buf size for socket,>=10 and <=10240,unit:kbyte,default:1024
    --force-sock-buf                      bypass system limitation while setting sock-buf
    --seq-mode            <number>        seq increase mode for faketcp:
                                          0:static header,do not increase seq and ack_seq
                                          1:increase seq for every packet,simply ack last seq
                                          2:increase seq randomly, about every 3 packets,simply ack last seq
                                          3:simulate an almost real seq/ack procedure(default)
                                          4:similiar to 3,but do not consider TCP Option Window_Scale,
                                          maybe useful when firewall doesnt support TCP Option
    --lower-level         <string>        send packets at OSI level 2, format:'if_name#dest_mac_adress'
                                          ie:'eth0#00:23:45:67:89:b9'.or try '--lower-level auto' to obtain
                                          the parameter automatically,specify it manually if 'auto' failed
    --wait-lock                           wait for xtables lock while invoking iptables, need iptables v1.4.20+
    --gen-add                             generate iptables rule and add it permanently,then exit.overrides -g
    --keep-rule                           monitor iptables and auto re-add if necessary.implys -a
    --hb-len              <number>        length of heart-beat packet, >=0 and <=1500
    --mtu-warn            <number>        mtu warning threshold, unit:byte, default:1375
    --clear                               clear any iptables rules added by this program.overrides everything
    --retry-on-error                      retry on error, allow to start udp2raw before network is initialized
    -h,--help                             print this help message
```

### iptables 规则,`-a`和`-g`
用raw收发tcp包本质上绕过了linux内核的tcp协议栈。linux碰到raw socket发来的包会不认识,如果一直收到不认识的包,会回复大量RST,造成不稳定或性能问题。所以强烈建议添加iptables规则屏蔽Linux内核的对指定端口的处理。用-a选项,udp2raw会在启动的时候自动帮你加上Iptables规则,退出的时候再自动删掉。如果长期使用,可以用-g选项来生成相应的Iptables规则再自己手动添加,这样规则不会在udp2raw退出时被删掉,可以避免停掉udp2raw后内核向对端回复RST。

用raw收发udp包也类似,只是内核回复的是icmp unreachable。而用raw 收发icmp,内核会自动回复icmp echo。都需要相应的iptables规则。
### `--cipher-mode` 和 `--auth-mode` 
如果要最大的安全性建议用aes128cbc+hmac_sha1。如果要运行在路由器上,建议用xor+simple,可以节省CPU。但是注意xor+simple只能骗过防火墙的包检测,不能防止真正的攻击者。

### `--seq-mode`
faketcp模式并没有模拟tcp的全部。所以理论上有办法把faketcp和真正的tcp流量区分开来(虽然大部分ISP不太可能做这种程度的包检测)。seq-mode可以改变一些seq ack的行为。如果遇到了连接问题,可以尝试更改。在我这边的移动线路用3种模式都没问题。

### `--keep-rule`
定期主动检查iptables,如果udp2raw添加的iptables规则丢了,就重新添加。在一些iptables可能会被其他程序清空的情况下(比如梅林固件和openwrt的路由器)格外有用。

### `--fifo`
指定一个fifo(named pipe)来向运行中的程序发送命令,例如`--fifo fifo.file`:

在client端,可以用`echo reconnect >fifo.file`来强制client换端口重连(上层不断线).对Server,目前没有效果。

### `--lower-level`
大部分udp2raw不能连通的情况都是设置了不兼容的iptables造成的。--lower-level选项允许绕过本地iptables。在一些iptables不好改动的情况下尤其有效(比如你用的是梅林固件,iptables全是固件自己生成的)。

##### 格式
`if_name#dest_mac_adress`,例如 `eth0#00:23:45:67:89:b9` 。`eth0`换成你的出口网卡名。`00:23:45:67:89:b9`换成网关的mac地址(如果client和server在同一个局域网内,可能不需要网关,这时候直接用对方主机的mac地址,这个属于罕见的应用场景,可以忽略)。

可以用`--lower-level auto`自动获取参数,如果获取参数失败,再手动填写。

##### client端获得--lower-level参数的办法
在client 端,运行`traceroute <server_ip>`,记下第一跳的地址,这个就是`网关ip`。再运行`arp -s <网关ip>`,可以同时查到出口网卡名和mac。

![](/images/lower_level.PNG)

如果traceroute第一跳结果是`* * *`,说明网关屏蔽了对traceroute的应答。需要用`ip route`或`route`查询网关:

![](/images/route.PNG)
##### server端获得--lower-level参数的办法
如果client有公网ip,就`traceroute <client_ip>`。下一步和client端的方法一样。

如果client没有公网ip,就`traceroute google.com` 或`traceroute baidu.com`。下一步和client端的方法一样。

server端也可以用`--lower-level auto` 来尝试自动获得参数,如果无法连接再手动填写。

##### 注意
如果用了`--lower-level`选项。server虽然还可以bind在0.0.0.0,但是因为你显式指定了网络接口,就只能工作在这一个网络接口了。

如果`arps -s`命令查询不到,首先再试几次。如果还是查询不到,那么可能是因为你用的是pppoe方式的拨号宽带,查询不到是正常的。这种情况下`if_name`填pppoe产生的虚拟interface,通常名字叫`pppXXXX`,从`ifconfig`命令的输出里找一下;`des_mac_adress`填`00:00:00:00:00:00`,例如`ppp0#00:00:00:00:00:00`

### `--conf-file`

为了避免将密码等私密信息暴露给`ps`命令,你也可以使用 `配置文件` 来存储参数。

比如,将以上服务端参数改写成配置文件

`server.conf`:

```
-s
# 你可以像这样添加注释
# 注意,只有整行注释才能在配置文件里使用
# 注释必须独占一行
-l 0.0.0.0:4096
-r 127.0.0.1:7777
-a
-k passwd
--raw-mode faketcp
```

注意,当写入配置文件的时候,密码等参数两边的引号必须去除。

然后就可以使用下面的方式启动服务端

```bash
./udp2raw_amd64 --conf-file server.conf
```

# 性能测试
iperf3 的UDP模式有BUG,所以,这里用iperf3的tcp模式,配合Openvpn,测试udp2raw的性能。(iperf3 udp issue ,https://github.com/esnet/iperf/issues/296 )

openvpn关掉了自带的加密。
#### iperf3 命令: 
```
iperf3 -c 10.222.2.1 -P40 
iperf3 -c 10.222.2.1 -P40 -R
```
#### client主机
vultr 2.5美元每月套餐(single core 2.4ghz cpu,512m ram,日本东京机房),
#### server主机
bandwagonhost 3.99美元每年套餐(single core 2.0ghz cpu,128m ram,美国洛杉矶机房)
### 测试1
raw_mode: faketcp  cipher_mode: xor  auth_mode: simple

![image4](/images/image4.PNG)

(反向的速度几乎一样,所以只发正向测试的图)

测试中cpu被打满。其中有30%的cpu是被openvpn占的。 如果不用Openvpn中转,实际达到100+Mb/S 应该没问题。

### 测试2
raw_mode: faketcp  cipher_mode: aes128cbc  auth_mode: md5

![image5](/images/image5.PNG)

(反向的速度几乎一样,所以只发正向测试的图)

测试中cpu被打满。绝大多数cpu都是被udp2raw占用的(主要消耗在aes加密)。即使不用Openvpn,速度也不会快很多了。
# 应用
### 中转 kcptun
[udp2raw+kcptun step_by_step教程](kcptun_step_by_step.md)
### 中转 finalspeed
[udp2raw+finalspeed step_by_step教程](finalspeed_step_by_step.md)

# wiki

更多内容请看 wiki:

https://github.com/wangyu-/udp2raw-tunnel/wiki




================================================
FILE: doc/android_guide.md
================================================
# How to run udp2raw on a rooted android device(arm cpu)

There is currently no GUI for udp2raw on android.Make sure you have installed Terminal to run it.Your device has to be rooted,otherwise you cant use raw socket.

Download udp2raw_arm from https://github.com/wangyu-/udp2raw-tunnel/releases.

Copy udp2raw_arm to any dir of your **internal storage** .Copying it to **SD card wont work**.

# Steps
1.  run udp2raw_arm  as usual, except you must change the -a option to -g
```
./udp2raw_arm -c -r 44.55.66.77:9966 -l 0.0.0.0:4000 -k1234 --cipher xor -g
```

2. find the generated iptables rule from udp2raw's output,add it manually by running:
```
iptables -I INPUT -s 44.55.66.77/32 -p tcp -m tcp --sport 9966 -j DROP
```

3. run udp2raw_ram without -g command

```
./udp2raw_arm -c -r 44.55.66.77:9966 -l 0.0.0.0:4000 -k1234 --cipher xor 
```

# ScreenShot 
zoom-in if not large enough

![](/images/android.png)


================================================
FILE: doc/build_guide.md
================================================
# udp2raw build guide

the guide on how to build udp2raw

## Build udp2raw for a specific platform

### linux platform which supports local compile
such as PC,raspberry pi

##### install git
run on debian/ubuntun:
```
sudo apt-get install git
```
run on redhat/centos:
```
sudo yum install git
```
##### clone git code

run in any dir:

```
git clone https://github.com/wangyu-/udp2raw-tunnel.git
cd udp2raw-tunnel
```

##### install compile tool
run on debian/ubuntun:
```
sudo apt-get install build-essential
```

run on redhat/centos:
```
sudo yum groupinstall 'Development Tools'
```

run 'make',compilation done. the udp2raw file is the just compiled binary

### platform which needs cross-compile
such as openwrt router,run following instructions on your PC

##### install git
run on debian/ubuntun:
```
sudo apt-get install git
```
run on redhat/centos:
```
sudo yum install git
```

##### download cross compile tool chain

find it on downloads.openwrt.org according to your openwrt version and cpu model.

for example, my tplink wdr4310 runs chaos_calmer 15.05,its with ar71xx cpu,download the following package.

```
http://downloads.openwrt.org/chaos_calmer/15.05/ar71xx/generic/OpenWrt-SDK-15.05-ar71xx-generic_gcc-4.8-linaro_uClibc-0.9.33.2.Linux-x86_64.tar.bz2
```
unzip it to any dir,such as :/home/wangyu/OpenWrt-SDK-ar71xx-for-linux-x86_64-gcc-4.8-linaro_uClibc-0.9.33.2

cd into staging_dir ,toolchain-xxxxx ,bin .find the soft link with g++ suffix. in my case ,its mips-openwrt-linux-g++ ,check for its full path:

```
/home/wangyu/Desktop/OpenWrt-SDK-15.05-ar71xx-generic_gcc-4.8-linaro_uClibc-0.9.33.2.Linux-x86_64/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-g++
```
##### compile
modify first line of makefile to:
```
cc_cross=/home/wangyu/Desktop/OpenWrt-SDK-15.05-ar71xx-generic_gcc-4.8-linaro_uClibc-0.9.33.2.Linux-x86_64/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-g++
```

run `make cross`,the just generated `udp2raw_cross` is the binary,compile done. copy it to your router to run.

`make cross` generates non-static binary. If you have any problem on running it,try to compile a static binary by using `make cross2` or `make cross3`.If your toolchain supports static compiling, usually one of them will succeed. The generated file is still named `udp2raw_cross`.



## Build a full release (include all binaries supported in the makefile)

1. make sure your linux is amd64 version

2. clone the repo

3. make sure you have g++ , make sure your g++ support the `-m32` option; make your your have installed libraries for `-m32` option

4. download https://github.com/wangyu-/files/releases/download/files/toolchains.tar.gz , and extract it to the right position (according to the makefile)

5. run `make release` inside udp2raw's directory


================================================
FILE: doc/build_guide.zh-cn.md
================================================
# udp2raw编译方法
本文演示怎么把udp2raw编译到自己所需的平台。

## 可以本地编译的linux平台
比如电脑、树莓派

##### 首先安装git
debian/ubuntun执行:
```
sudo apt-get install git
```
redhat/centos执行:
```
sudo yum install git
```
##### 用git把源码clone至本地

在任意目录执行:

```
git clone https://github.com/wangyu-/udp2raw-tunnel.git
cd udp2raw-tunnel
```

##### 安装g++ make 等工具
debian/ubuntun执行:
```
sudo apt-get install build-essential
```

redhat/centos执行:
```
sudo yum groupinstall 'Development Tools'
```

然后运行make,编译完成。 生成的udp2raw就是编译好的bianry。

## 需要交叉编译的平台
比如各种openwrt路由器

##### 首先安装git
debian/ubuntun执行:
```
sudo apt-get install git
```
redhat/centos执行:
```
sudo yum install git
```

##### 下载安装交叉编译工具包
去downloads.openwrt.org上找到自己的openwrt版本和cpu型号对应的SDK。通常openwrt版本号不一样也问题不大,最主要是cpu型号。

比如我的tplink wdr4310运行的是chaos_calmer 15.05,ar71xx cpu,应该下载这个包:

```
http://downloads.openwrt.org/chaos_calmer/15.05/ar71xx/generic/OpenWrt-SDK-15.05-ar71xx-generic_gcc-4.8-linaro_uClibc-0.9.33.2.Linux-x86_64.tar.bz2
```
解压到本地任意目录,比如:/home/wangyu/OpenWrt-SDK-ar71xx-for-linux-x86_64-gcc-4.8-linaro_uClibc-0.9.33.2

让后依次进入,staging_dir ,toolchain-xxxxx ,bin 目录,找到后缀是g++的软链,比如我的是mips-openwrt-linux-g++ ,记下这个文件的完整路径:

```
/home/wangyu/Desktop/OpenWrt-SDK-15.05-ar71xx-generic_gcc-4.8-linaro_uClibc-0.9.33.2.Linux-x86_64/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-g++
```
##### 编译
把makefile的第一行 cross_cc=后面的内容改成你刚才记下的完整路径:
```
cc_cross=/home/wangyu/Desktop/OpenWrt-SDK-15.05-ar71xx-generic_gcc-4.8-linaro_uClibc-0.9.33.2.Linux-x86_64/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-g++
```

执行`make cross`,目录下生成udp2raw_cross文件。编译完成。

`make cross`编译出的binary是非静态的。如果运行有问题,可以尝试用`make cross2`或`make cross3`编译静态的binary,你的工具链必须带静态库才能成功编译,生成的文件仍然叫udp2raw_cross.


================================================
FILE: doc/finalspeed_step_by_step/11
================================================
11


================================================
FILE: doc/finalspeed_step_by_step.md
================================================
# udp2raw+finalspeed 加速tcp流量 Step by Step 教程
![image](finalspeed_step_by_step/Capture0.PNG)

##### 背景
国内有些ISP会对UDP做QOS或屏蔽,这时候加速协议对TCP发包模式的支持就很重要。finalspeed虽然本身支持在底层用TCP发包,但是其依赖的libpcap不支持openvz架构,即使不是openvz架构的主机,也存在不稳定的问题。


##### 摘要
udp2raw是一个把udp流量通过raw socket包装成tcp流量的工具。通过用udp2raw配合udp模式的 finalspeed一样可以达到在底层发tcp包,绕过QOS的效果。支持openvz,稳定性也好很多。原理上相当于在finalspeed外面再包了一层tunnel。

本教程会一步一步演示用udp2raw+finalspeed加速http流量的过程。加速任何其他tcp流量也一样,包括$\*\*\*。本文避免讨论科学上网,所以只演示加速http流量。

udp2raw也支持把udp流量包装成Icmp发送,本教程不做演示。

### 环境要求
服务器主机是linux,有root权限。  可以是openvz架构的vps。 也可以是openwrt路由器。

本地主机是windows,本地有openwrt路由器或树莓派或安装了linux虚拟机(网卡设置为桥接模式)。

(如果嫌给虚拟机安装linux麻烦,可以用release里发布的预装了udp2raw的openwrt_x86虚拟机镜像,容量4.4mb)

下面的教程按虚拟机演示,如果你有openwrt路由器或树莓派,可以直接运行再路由器或树莓派上,就不需要虚拟机了。

### 安装
下载好udp2raw的压缩包,解压分别解压到服务器和本地的虚拟机。

https://github.com/wangyu-/udp2raw-tunnel/releases

在服务器端安装好finalspeed服务端,在本地windows安装好finalspeed的客户端。服务端我以前是用91yun的一键安装脚本安装的,没装过的可以去网上搜一键安装脚本。

### 运行
1.先在服务器主机运行如下命令,确定finalspeed服务端已经正常启动了。

```
netstat -nlp|grep java
```
![image](finalspeed_step_by_step/Capture5.PNG)

如果显示了150端口,就表示服务端启动好了。

2.在服务器启动udp2raw server
```
 ./udp2raw_amd64 -s -l0.0.0.0:8855 -r 127.0.0.1:150  -a -k "passwd" --raw-mode faketcp
```
![image](finalspeed_step_by_step/Capture2.PNG)

3.在本地的虚拟机上启动udp2raw client  ,假设服务器ip是45.66.77.88
```
./udp2raw_amd64 -c -r45.66.77.88:8855 -l0.0.0.0:150 --raw-mode faketcp -a -k"passwd"
```
如果一切正常,client端会显示client_ready:

![image](finalspeed_step_by_step/Capture3.PNG)

记下红框中的ip,这是虚拟机的网卡ip

在server端也会显示server_ready
![image](finalspeed_step_by_step/Capture4.PNG)

4.在本地windows,按图配置好finalspeed的客户端。注意,192.168.205.8改成你刚才记下来的IP,带宽也要按实际的填。传输协议要选UDP.
![image](finalspeed_step_by_step/Capture.PNG)

5.所有准备工作已经完成了,在本地访问本地的8012端口,相当于访问服务器的80端口。

来试一下通过http://127.0.0.1:8012/ 下载文件 ,1.5M/s:
![image](finalspeed_step_by_step/Capture6.PNG)

再试一下直接通过服务器的ip访问,http://45.66.77.88:80/ ,速度只有600K/s
![image](finalspeed_step_by_step/Capture7.PNG)

教程就到这里了,用来加速其他的tcp服务也是一样的,只要再第三步那里设置其他的端口。


================================================
FILE: doc/kcptun_step_by_step.md
================================================
# udp2raw+kcptun 加速tcp流量 Step by Step 教程
![image](kcptun_step_by_step/Capture00.PNG)

本教程会一步一步演示用udp2raw+kcptun加速SSH流量的过程。加速任何其他tcp流量也一样,包括$\*\*\*;本文避免涉及科学上网,所以演示ssh。

### 环境要求
两边的主机都是linux,有root权限。 可以是openwrt路由器或树莓派,也可以是root了的android。

在windows/mac上运行udp2raw可以参考这个教程:

https://github.com/wangyu-/udp2raw-tunnel/wiki/在windows-mac上运行udp2raw客户端,带图形界面


### 安装
下载好kcptun和udp2raw的压缩包,解压分别解压到client端和server端。

https://github.com/xtaci/kcptun/releases
https://github.com/wangyu-/udp2raw-tunnel/releases

解压好后,如图:
![image](kcptun_step_by_step/Capture0.PNG)

### 运行
1.在远程服务器运行 udp2raw_amd64 server模式:
```
./udp2raw_amd64 -s -l0.0.0.0:8855 -r 127.0.0.1:4000 -k "passwd" --raw-mode faketcp -a
```
![image](kcptun_step_by_step/Capture.PNG)

2.在本地运行udp2raw_amd64 client模式,假设server ip是45.66.77.88:
```
./udp2raw_amd64 -c -r45.66.77.88:8855 -l0.0.0.0:4000 --raw-mode faketcp -a -k"passwd"
```
如果一切正常client端输出如下,显示client_ready:
![image](kcptun_step_by_step/Capture2.PNG)

server端也会有类似输出,显示server_ready:
![image](kcptun_step_by_step/Capture3.PNG)

3.在远程服务器运行 kcp server


```
./server_linux_amd64 -t "127.0.0.1:22" -l ":4000" -mode fast2 -mtu 1300
```
-mtu 1300很重要,或者设置成更小。
![image](kcptun_step_by_step/Capture6.PNG)

4.在本地运行 


```
 ./client_linux_amd64 -r "127.0.0.1:4000" -l ":3322" -mode fast2 -mtu 1300
```
-mtu 1300很重要,或者设置成更小。
![image](kcptun_step_by_step/Capture7.PNG)

5.所有准备工作已经做好,在本地运行
```
ssh -p 3322 root@127.0.0.1
```
已经连进去了,而且是经过kcptun加速的:
![image](kcptun_step_by_step/Capture8.PNG)


================================================
FILE: doc/openvpn_guide.md
================================================
# udp2raw+openvpn config guide
![image_vpn](/images/openvpn.PNG)

![image4](/images/image4.PNG)

# udp2raw command
#### run at server side
```
./udp2raw_amd64 -s -l0.0.0.0:8855 -r 127.0.0.1:7777 -k "passwd" --raw-mode faketcp -a
```
#### run at client side
assume server ip is 45.66.77.88
```
./udp2raw_amd64 -c -l0.0.0.0:3333 -r 45.66.77.88:8855 -k "passwd" --raw-mode faketcp -a
```

#### hint
You can add `--cipher-mode xor` `--auth-mode simple` to **both** sides to obtain maximum performance(but poor security).

# openvpn config

#### client side config
```
client
dev tun100
proto udp

remote 127.0.0.1 3333
resolv-retry infinite 
nobind 
persist-key 
persist-tun  

ca /root/add-on/openvpn/ca.crt
cert /root/add-on/openvpn/client.crt
key /root/add-on/openvpn/client.key

keepalive 3 20
verb 3
mute 20

comp-lzo no
cipher none      ##### disable openvpn 's cipher and auth for maxmized peformance. 
auth none        ##### you can enable openvpn's cipher and auth,if you dont care about peformance,or you dont trust udp2raw 's encryption

fragment 1200       ##### very important    you can turn it up a bit. but,the lower the safer
mssfix 1200         ##### very important

sndbuf 2000000      ##### important
rcvbuf 2000000      ##### important
txqueuelen 4000     ##### suggested
```


#### server side config
```
local 0.0.0.0
port 7777 
proto udp
dev tun 

ca /etc/openvpn/easy-rsa/2.0/keys/ca.crt
cert /etc/openvpn/easy-rsa/2.0/keys/server.crt
key /etc/openvpn/easy-rsa/2.0/keys/server.key
dh /etc/openvpn/easy-rsa/2.0/keys/dh1024.pem

server 10.222.2.0 255.255.255.0 
ifconfig 10.222.2.1 10.222.2.6

client-to-client
duplicate-cn 
keepalive 10 60 

max-clients 50

persist-key
persist-tun

status /etc/openvpn/openvpn-status.log

verb 3
mute 20  

comp-lzo no
cipher none      ##### disable openvpn 's cipher and auth for maxmized peformance. 
auth none        ##### you can enable openvpn's cipher and auth,if you dont care about peformance,or you dont trust udp2raw 's encryption

fragment 1200       ##### very important    you can turn it up a bit. but,the lower the safer
mssfix 1200         ##### very important

sndbuf 2000000      ##### important
rcvbuf 2000000      ##### important
txqueuelen 4000     ##### suggested
```


================================================
FILE: encrypt.cpp
================================================
#include "lib/aes-common.h"
#include "lib/md5.h"
#include "lib/pbkdf2-sha1.h"
#include "lib/pbkdf2-sha256.h"
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include "encrypt.h"
#include "common.h"
#include "log.h"

// static uint64_t seq=1;

static int8_t zero_iv[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};  // this prog use zero iv,you should make sure first block of data contains a random/nonce data
/****
 * security of zero_iv + nonce first data block
 * https://crypto.stackexchange.com/questions/5421/using-cbc-with-a-fixed-iv-and-a-random-first-plaintext-block
 ****/

char normal_key[16 + 100];    // generated from key_string by md5. reserved for compatiblity
const int hmac_key_len = 64;  // generate 512bit long keys, use first n chars when needed
const int cipher_key_len = 64;
unsigned char hmac_key_encrypt[hmac_key_len + 100];      // key for hmac
unsigned char hmac_key_decrypt[hmac_key_len + 100];      // key for hmac
unsigned char cipher_key_encrypt[cipher_key_len + 100];  // key for aes etc.
unsigned char cipher_key_decrypt[cipher_key_len + 100];  // key for aes etc.

char gro_xor[256 + 100];  // dirty fix for gro

unordered_map<int, const char *> auth_mode_tostring = {
    {auth_none, "none"},
    {auth_md5, "md5"},
    {auth_crc32, "crc32"},
    {auth_simple, "simple"},
    {auth_hmac_sha1, "hmac_sha1"},
};

unordered_map<int, const char *> cipher_mode_tostring = {
    {cipher_none, "none"},
    {cipher_aes128cfb, "aes128cfb"},
    {cipher_aes128cbc, "aes128cbc"},
    {cipher_xor, "xor"},
};
// TODO aes-gcm

auth_mode_t auth_mode = auth_md5;
cipher_mode_t cipher_mode = cipher_aes128cbc;
int is_hmac_used = 0;

int aes128cfb_old = 0;

// TODO key negotiation and forward secrecy

int my_init_keys(const char *user_passwd, int is_client) {
    char tmp[1000] = "";
    int len = strlen(user_passwd);

    strcat(tmp, user_passwd);

    strcat(tmp, "key1");

    md5((uint8_t *)tmp, strlen(tmp), (uint8_t *)normal_key);

    if (auth_mode == auth_hmac_sha1)
        is_hmac_used = 1;
    if (is_hmac_used || g_fix_gro || 1) {
        unsigned char salt[400] = "";
        char salt_text[400] = "udp2raw_salt1";
        md5((uint8_t *)(salt_text), strlen(salt_text), salt);  // TODO different salt per session

        unsigned char pbkdf2_output1[400] = "";
        PKCS5_PBKDF2_HMAC_SHA256((uint8_t *)user_passwd, len, salt, 16, 10000, 32, pbkdf2_output1);  // TODO argon2 ?

        // unsigned char pbkdf2_output2[400]="";
        // PKCS5_PBKDF2_HMAC_SHA256(pbkdf2_output1,32,0,0,1, hmac_key_len*2+cipher_key_len*2,pbkdf2_output2);  //stretch it

        const char *info_hmac_encrypt = "hmac_key server-->client";
        const char *info_hmac_decrypt = "hmac_key client-->server";
        const char *info_cipher_encrypt = "cipher_key server-->client";
        const char *info_cipher_decrypt = "cipher_key client-->server";

        if (is_client) {
            const char *tmp;
            tmp = info_hmac_encrypt;
            info_hmac_encrypt = info_hmac_decrypt;
            info_hmac_decrypt = tmp;
            tmp = info_cipher_encrypt;
            info_cipher_encrypt = info_cipher_decrypt;
            info_cipher_decrypt = tmp;
        } else {
            // nop
        }

        assert(hkdf_sha256_expand(pbkdf2_output1, 32, (unsigned char *)info_cipher_encrypt, strlen(info_cipher_encrypt), cipher_key_encrypt, cipher_key_len) == 0);
        assert(hkdf_sha256_expand(pbkdf2_output1, 32, (unsigned char *)info_cipher_decrypt, strlen(info_cipher_decrypt), cipher_key_decrypt, cipher_key_len) == 0);
        assert(hkdf_sha256_expand(pbkdf2_output1, 32, (unsigned char *)info_hmac_encrypt, strlen(info_hmac_encrypt), hmac_key_encrypt, hmac_key_len) == 0);
        assert(hkdf_sha256_expand(pbkdf2_output1, 32, (unsigned char *)info_hmac_decrypt, strlen(info_hmac_decrypt), hmac_key_decrypt, hmac_key_len) == 0);

        const char *gro_info = "gro";
        assert(hkdf_sha256_expand(pbkdf2_output1, 32, (unsigned char *)gro_info, strlen(gro_info), (unsigned char *)gro_xor, 256) == 0);
    }

    print_binary_chars(normal_key, 16);
    print_binary_chars((char *)hmac_key_encrypt, hmac_key_len);
    print_binary_chars((char *)hmac_key_decrypt, hmac_key_len);
    print_binary_chars((char *)cipher_key_encrypt, cipher_key_len);
    print_binary_chars((char *)cipher_key_decrypt, cipher_key_len);

    return 0;
}
/*
 *  this function comes from  http://www.hackersdelight.org/hdcodetxt/crc.c.txt
 */
unsigned int crc32h(unsigned char *message, int len) {
    int i, crc;
    unsigned int byte, c;
    const unsigned int g0 = 0xEDB88320, g1 = g0 >> 1,
                       g2 = g0 >> 2, g3 = g0 >> 3, g4 = g0 >> 4, g5 = g0 >> 5,
                       g6 = (g0 >> 6) ^ g0, g7 = ((g0 >> 6) ^ g0) >> 1;

    i = 0;
    crc = 0xFFFFFFFF;
    while (i != len) {  // Get next byte.
        byte = message[i];
        crc = crc ^ byte;
        c = ((crc << 31 >> 31) & g7) ^ ((crc << 30 >> 31) & g6) ^
            ((crc << 29 >> 31) & g5) ^ ((crc << 28 >> 31) & g4) ^
            ((crc << 27 >> 31) & g3) ^ ((crc << 26 >> 31) & g2) ^
            ((crc << 25 >> 31) & g1) ^ ((crc << 24 >> 31) & g0);
        crc = ((unsigned)crc >> 8) ^ c;
        i = i + 1;
    }
    return ~crc;
}

/*
 void sum(const unsigned  char *data,int len,unsigned char*  res) {
   memset(res,0,sizeof(int));
   for(int i=0,j=0;i<len;i++,j++)
   {
           if(j==4) j=0;
           res[j]+=data[i];
   }

   return ;
}*/

void simple_hash(unsigned char *str, int len, unsigned char res[8])  // djb2+ sdbm
{
    u32_t hash = 5381;
    u32_t hash2 = 0;
    int c;
    int i = 0;
    while (c = *str++, i++ != len) {
        // hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
        hash = ((hash << 5) + hash) ^ c; /* (hash * 33) ^ c */
        hash2 = c + (hash2 << 6) + (hash2 << 16) - hash2;
    }

    hash = htonl(hash);
    hash2 = htonl(hash2);
    memcpy(res, &hash, sizeof(hash));
    memcpy(res + sizeof(hash), &hash2, sizeof(hash2));
}

int auth_md5_cal(const char *data, char *output, int &len) {
    memcpy(output, data, len);  // TODO inefficient code
    md5((unsigned char *)output, len, (unsigned char *)(output + len));
    len += 16;
    return 0;
}

int auth_hmac_sha1_cal(const char *data, char *output, int &len) {
    mylog(log_trace, "auth_hmac_sha1_cal() is called\n");
    memcpy(output, data, len);  // TODO inefficient code
    sha1_hmac(hmac_key_encrypt, 20, (const unsigned char *)data, len, (unsigned char *)(output + len));
    // use key len of 20 instead of hmac_key_len, "extra length would not significantly increase the function strength" (rfc2104)
    len += 20;
    return 0;
}

int auth_hmac_sha1_verify(const char *data, int &len) {
    mylog(log_trace, "auth_hmac_sha1_verify() is called\n");
    if (len < 20) {
        mylog(log_trace, "auth_hmac_sha1_verify len<20\n");
        return -1;
    }
    char res[20];

    sha1_hmac(hmac_key_decrypt, 20, (const unsigned char *)data, len - 20, (unsigned char *)(res));

    if (memcmp(res, data + len - 20, 20) != 0) {
        mylog(log_trace, "auth_hmac_sha1 check failed\n");
        return -2;
    }
    len -= 20;
    return 0;
}

int auth_crc32_cal(const char *data, char *output, int &len) {
    memcpy(output, data, len);  // TODO inefficient code
    unsigned int ret = crc32h((unsigned char *)output, len);
    unsigned int ret_n = htonl(ret);
    memcpy(output + len, &ret_n, sizeof(unsigned int));
    len += sizeof(unsigned int);
    return 0;
}

int auth_simple_cal(const char *data, char *output, int &len) {
    // char res[4];
    memcpy(output, data, len);  // TODO inefficient code
    simple_hash((unsigned char *)output, len, (unsigned char *)(output + len));
    len += 8;
    return 0;
}
int auth_simple_verify(const char *data, int &len) {
    if (len < 8) return -1;
    unsigned char res[8];
    len -= 8;
    simple_hash((unsigned char *)data, len, res);
    if (memcmp(res, data + len, 8) != 0)
        return -1;
    return 0;
}

int auth_none_cal(const char *data, char *output, int &len) {
    memcpy(output, data, len);
    return 0;
}
int auth_md5_verify(const char *data, int &len) {
    if (len < 16) {
        mylog(log_trace, "auth_md5_verify len<16\n");
        return -1;
    }
    char md5_res[16];

    md5((unsigned char *)data, len - 16, (unsigned char *)md5_res);

    if (memcmp(md5_res, data + len - 16, 16) != 0) {
        mylog(log_trace, "auth_md5_verify md5 check failed\n");
        return -2;
    }
    len -= 16;
    return 0;
}
int auth_none_verify(const char *data, int &len) {
    return 0;
}

int cipher_xor_encrypt(const char *data, char *output, int &len, char *key) {
    int i, j;
    for (i = 0, j = 0; i < len; i++, j++) {
        if (j == 16) j = 0;
        output[i] = data[i] ^ key[j];
    }
    return 0;
}
int cipher_xor_decrypt(const char *data, char *output, int &len, char *key) {
    int i, j;
    // char tmp[buf_len];
    // len=len/16*16+1;
    // AES128_CBC_decrypt_buffer((uint8_t *)tmp, (uint8_t *)input, len, (uint8_t *)key, (uint8_t *)iv);
    // for(i=0;i<len;i++)
    // input[i]=tmp[i];
    for (i = 0, j = 0; i < len; i++, j++) {
        if (j == 16) j = 0;
        output[i] = data[i] ^ key[j];
    }
    return 0;
}

int padding(char *data, int &data_len, int padding_num) {
    int old_len = data_len;
    data_len += 1;
    if (data_len % padding_num != 0) {
        data_len = (data_len / padding_num) * padding_num + padding_num;
    }
    unsigned char *p = (unsigned char *)&data[data_len - 1];
    *p = (data_len - old_len);
    return 0;
}

int de_padding(const char *data, int &data_len, int padding_num) {
    if (data_len == 0) return -1;
    if ((uint8_t)data[data_len - 1] > padding_num) return -1;
    data_len -= (uint8_t)data[data_len - 1];
    if (data_len < 0) {
        return -1;
    }
    return 0;
}
void aes_ecb_encrypt(const char *data, char *output) {
    static int first_time = 1;
    char *key = (char *)cipher_key_encrypt;
    if (aes_key_optimize) {
        if (first_time == 0)
            key = 0;
        else
            first_time = 0;
    }
    AES_ECB_encrypt_buffer((uint8_t *)data, (uint8_t *)key, (uint8_t *)output);
}
void aes_ecb_encrypt1(char *data) {
    char buf[16];
    memcpy(buf, data, 16);
    aes_ecb_encrypt(buf, data);
}
void aes_ecb_decrypt(const char *data, char *output) {
    static int first_time = 1;
    char *key = (char *)cipher_key_decrypt;
    if (aes_key_optimize) {
        if (first_time == 0)
            key = 0;
        else
            first_time = 0;
    }
    AES_ECB_decrypt_buffer((uint8_t *)data, (uint8_t *)key, (uint8_t *)output);
}
void aes_ecb_decrypt1(char *data) {
    char buf[16];
    memcpy(buf, data, 16);
    aes_ecb_decrypt(buf, data);
}
int cipher_aes128cbc_encrypt(const char *data, char *output, int &len, char *key) {
    static int first_time = 1;

    char buf[buf_len];
    memcpy(buf, data, len);  // TODO inefficient code

    if (padding(buf, len, 16) < 0) return -1;

    if (aes_key_optimize) {
        if (first_time == 0)
            key = 0;
        else
            first_time = 0;
    }

    AES_CBC_encrypt_buffer((unsigned char *)output, (unsigned char *)buf, len, (unsigned char *)key, (unsigned char *)zero_iv);
    return 0;
}
int cipher_aes128cfb_encrypt(const char *data, char *output, int &len, char *key) {
    static int first_time = 1;
    assert(len >= 16);

    char buf[buf_len];
    memcpy(buf, data, len);  // TODO inefficient code
    if (aes_key_optimize) {
        if (first_time == 0)
            key = 0;
        else
            first_time = 0;
    }
    if (!aes128cfb_old) {
        aes_ecb_encrypt(data, buf);  // encrypt the first block
    }

    AES_CFB_encrypt_buffer((unsigned char *)output, (unsigned char *)buf, len, (unsigned char *)key, (unsigned char *)zero_iv);
    return 0;
}
int auth_crc32_verify(const char *data, int &len) {
    if (len < int(sizeof(unsigned int))) {
        mylog(log_debug, "auth_crc32_verify len<%d\n", int(sizeof(unsigned int)));
        return -1;
    }
    unsigned int ret = crc32h((unsigned char *)data, len - sizeof(unsigned int));
    unsigned int ret_n = htonl(ret);

    if (memcmp(data + len - sizeof(unsigned int), &ret_n, sizeof(unsigned int)) != 0) {
        mylog(log_debug, "auth_crc32_verify memcmp fail\n");
        return -1;
    }
    len -= sizeof(unsigned int);
    return 0;
}
int cipher_none_encrypt(const char *data, char *output, int &len, char *key) {
    memcpy(output, data, len);
    return 0;
}
int cipher_aes128cbc_decrypt(const char *data, char *output, int &len, char *key) {
    static int first_time = 1;
    if (len % 16 != 0) {
        mylog(log_debug, "len%%16!=0\n");
        return -1;
    }
    if (aes_key_optimize) {
        if (first_time == 0)
            key = 0;
        else
            first_time = 0;
    }
    AES_CBC_decrypt_buffer((unsigned char *)output, (unsigned char *)data, len, (unsigned char *)key, (unsigned char *)zero_iv);
    if (de_padding(output, len, 16) < 0) return -1;
    return 0;
}
int cipher_aes128cfb_decrypt(const char *data, char *output, int &len, char *key) {
    static int first_time = 1;
    if (len < 16) return -1;

    if (aes_key_optimize) {
        if (first_time == 0)
            key = 0;
        else
            first_time = 0;
    }

    AES_CFB_decrypt_buffer((unsigned char *)output, (unsigned char *)data, len, (unsigned char *)key, (unsigned char *)zero_iv);

    if (!aes128cfb_old)
        aes_ecb_decrypt1(output);  // decrypt the first block
    // if(de_padding(output,len,16)<0) return -1;
    return 0;
}

int cipher_none_decrypt(const char *data, char *output, int &len, char *key) {
    memcpy(output, data, len);
    return 0;
}

int auth_cal(const char *data, char *output, int &len) {
    mylog(log_trace, "auth:%d\n", auth_mode);
    switch (auth_mode) {
        case auth_crc32:
            return auth_crc32_cal(data, output, len);
        case auth_md5:
            return auth_md5_cal(data, output, len);
        case auth_simple:
            return auth_simple_cal(data, output, len);
        case auth_none:
            return auth_none_cal(data, output, len);
        case auth_hmac_sha1:
            return auth_hmac_sha1_cal(data, output, len);
        // default:	return auth_md5_cal(data,output,len);//default;
        default:
            assert(0 == 1);
    }
    return -1;
}
int auth_verify(const char *data, int &len) {
    mylog(log_trace, "auth:%d\n", auth_mode);
    switch (auth_mode) {
        case auth_crc32:
            return auth_crc32_verify(data, len);
        case auth_md5:
            return auth_md5_verify(data, len);
        case auth_simple:
            return auth_simple_verify(data, len);
        case auth_none:
            return auth_none_verify(data, len);
        case auth_hmac_sha1:
            return auth_hmac_sha1_verify(data, len);
        // default:	return auth_md5_verify(data,len);//default
        default:
            assert(0 == 1);
    }
    return -1;
}
int cipher_encrypt(const char *data, char *output, int &len, char *key) {
    mylog(log_trace, "cipher:%d\n", cipher_mode);
    switch (cipher_mode) {
        case cipher_aes128cbc:
            return cipher_aes128cbc_encrypt(data, output, len, key);
        case cipher_aes128cfb:
            return cipher_aes128cfb_encrypt(data, output, len, key);
        case cipher_xor:
            return cipher_xor_encrypt(data, output, len, key);
        case cipher_none:
            return cipher_none_encrypt(data, output, len, key);
        // default:return cipher_aes128cbc_encrypt(data,output,len, key);
        default:
            assert(0 == 1);
    }
    return -1;
}
int cipher_decrypt(const char *data, char *output, int &len, char *key) {
    mylog(log_trace, "cipher:%d\n", cipher_mode);
    switch (cipher_mode) {
        case cipher_aes128cbc:
            return cipher_aes128cbc_decrypt(data, output, len, key);
        case cipher_aes128cfb:
            return cipher_aes128cfb_decrypt(data, output, len, key);
        case cipher_xor:
            return cipher_xor_decrypt(data, output, len, key);
        case cipher_none:
            return cipher_none_decrypt(data, output, len, key);
        //	default:	return cipher_aes128cbc_decrypt(data,output,len,key);
        default:
            assert(0 == 1);
    }
    return -1;
}

int encrypt_AE(const char *data, char *output, int &len /*,char * key*/) {
    mylog(log_trace, "encrypt_AE is called\n");
    char buf[buf_len];
    char buf2[buf_len];
    memcpy(buf, data, len);
    if (cipher_encrypt(buf, buf2, len, (char *)cipher_key_encrypt) != 0) {
        mylog(log_debug, "cipher_encrypt failed ");
        return -1;
    }
    if (auth_cal(buf2, output, len) != 0) {
        mylog(log_debug, "auth_cal failed ");
        return -1;
    }

    // printf("%d %x %x\n",len,(int)(output[0]),(int)(output[1]));
    // print_binary_chars(output,len);

    // use encrypt-then-MAC scheme
    return 0;
}

int decrypt_AE(const char *data, char *output, int &len /*,char * key*/) {
    mylog(log_trace, "decrypt_AE is called\n");
    // printf("%d %x %x\n",len,(int)(data[0]),(int)(data[1]));
    // print_binary_chars(data,len);

    if (auth_verify(data, len) != 0) {
        mylog(log_debug, "auth_verify failed\n");
        return -1;
    }
    if (cipher_decrypt(data, output, len, (char *)cipher_key_decrypt) != 0) {
        mylog(log_debug, "cipher_decrypt failed \n");
        return -1;
    }
    return 0;
}

int my_encrypt(const char *data, char *output, int &len /*,char * key*/) {
    if (len < 0) {
        mylog(log_trace, "len<0");
        return -1;
    }
    if (len > max_data_len) {
        mylog(log_warn, "len>max_data_len");
        return -1;
    }

    if (is_hmac_used)
        return encrypt_AE(data, output, len);

    char buf[buf_len];
    char buf2[buf_len];
    memcpy(buf, data, len);
    if (auth_cal(buf, buf2, len) != 0) {
        mylog(log_debug, "auth_cal failed ");
        return -1;
    }
    if (cipher_encrypt(buf2, output, len, normal_key) != 0) {
        mylog(log_debug, "cipher_encrypt failed ");
        return -1;
    }
    return 0;
}

int my_decrypt(const char *data, char *output, int &len /*,char * key*/) {
    if (len < 0) return -1;
    if (len > max_data_len) {
        mylog(log_warn, "len>max_data_len");
        return -1;
    }

    if (is_hmac_used)
        return decrypt_AE(data, output, len);

    if (cipher_decrypt(data, output, len, normal_key) != 0) {
        mylog(log_debug, "cipher_decrypt failed \n");
        return -1;
    }
    if (auth_verify(output, len) != 0) {
        mylog(log_debug, "auth_verify failed\n");
        return -1;
    }

    return 0;
}

int encrypt_AEAD(uint8_t *data, uint8_t *output, int &len, uint8_t *key, uint8_t *header, int hlen) {
    // TODO
    return -1;
}

int decrypt_AEAD(uint8_t *data, uint8_t *output, int &len, uint8_t *key, uint8_t *header, int hlen) {
    // TODO
    return -1;
}


================================================
FILE: encrypt.h
================================================
#ifndef UDP2RAW_ENCRYPTION_H_
#define UDP2RAW_ENCRYPTION_H_

//#include "aes.h"
//#include "md5.h"
#include "common.h"

// using namespace std;
// extern char key[16];

const int aes_key_optimize = 1;  // if enabled,once you used a key for aes,you cant change it anymore
extern int aes128cfb_old;

int my_init_keys(const char *, int);

int my_encrypt(const char *data, char *output, int &len);
int my_decrypt(const char *data, char *output, int &len);

unsigned short csum(const unsigned short *ptr, int nbytes);

enum auth_mode_t { auth_none = 0,
                   auth_md5,
                   auth_crc32,
                   auth_simple,
                   auth_hmac_sha1,
                   auth_end };

enum cipher_mode_t { cipher_none = 0,
                     cipher_aes128cbc,
                     cipher_xor,
                     cipher_aes128cfb,
                     cipher_end };

extern auth_mode_t auth_mode;
extern cipher_mode_t cipher_mode;

extern unordered_map<int, const char *> auth_mode_tostring;
extern unordered_map<int, const char *> cipher_mode_tostring;

extern char gro_xor[256 + 100];

int cipher_decrypt(const char *data, char *output, int &len, char *key);  // internal interface ,exposed for test only
int cipher_encrypt(const char *data, char *output, int &len, char *key);  // internal interface ,exposed for test only

void aes_ecb_encrypt(const char *data, char *output);
void aes_ecb_decrypt(const char *data, char *output);

void aes_ecb_encrypt1(char *data);
void aes_ecb_decrypt1(char *data);

#endif


================================================
FILE: example.conf
================================================
# Basically this file is the equivalent to splitting the command line options into multiple lines
# Each line should contain an option

# This is client
-c
# Or use -s if you use it on server side
# Define local address
-l 127.0.0.1:56789
# Define remote address
-r 45.66.77.88:45678
# Password
-k my_awesome_password
# Mode
--raw-mode faketcp
# Log Level
--log-level 4


================================================
FILE: fd_manager.cpp
================================================
/*
 * fd_manager.cpp
 *
 *  Created on: Sep 25, 2017
 *      Author: root
 */

#include "fd_manager.h"
int fd_manager_t::fd_exist(int fd) {
    return fd_to_fd64_mp.find(fd) != fd_to_fd64_mp.end();
}
int fd_manager_t::exist(fd64_t fd64) {
    return fd64_to_fd_mp.find(fd64) != fd64_to_fd_mp.end();
}
int fd_manager_t::to_fd(fd64_t fd64) {
    assert(exist(fd64));
    return fd64_to_fd_mp[fd64];
}
void fd_manager_t::fd64_close(fd64_t fd64) {
    assert(exist(fd64));
    int fd = fd64_to_fd_mp[fd64];
    fd64_to_fd_mp.erase(fd64);
    fd_to_fd64_mp.erase(fd);
    if (exist_info(fd64)) {
        fd_info_mp.erase(fd64);
    }
    // assert(close(fd)==0);
    sock_close(fd);
}
void fd_manager_t::reserve(int n) {
    fd_to_fd64_mp.reserve(n);
    fd64_to_fd_mp.reserve(n);
    fd_info_mp.reserve(n);
}
u64_t fd_manager_t::create(int fd) {
    assert(!fd_exist(fd));
    fd64_t fd64 = counter++;
    fd_to_fd64_mp[fd] = fd64;
    fd64_to_fd_mp[fd64] = fd;
    return fd64;
}
fd_manager_t::fd_manager_t() {
    counter = u32_t(-1);
    counter += 100;
    reserve(10007);
}
fd_info_t& fd_manager_t::get_info(fd64_t fd64) {
    assert(exist(fd64));
    return fd_info_mp[fd64];
}
int fd_manager_t::exist_info(fd64_t fd64) {
    return fd_info_mp.find(fd64) != fd_info_mp.end();
}


================================================
FILE: fd_manager.h
================================================
/*
 * fd_manager.h
 *
 *  Created on: Sep 25, 2017
 *      Author: root
 */

#ifndef FD_MANAGER_H_
#define FD_MANAGER_H_

#include "common.h"
//#include "packet.h"
#include "connection.h"

struct fd_info_t {
    // ip_port_t ip_port;
    conn_info_t *p_conn_info;
};

struct fd_manager_t  // conver fd to a uniq 64bit number,avoid fd value conflict caused by close and re-create
// this class is not strictly necessary,it just makes epoll fd handling easier
{
    fd_info_t &get_info(fd64_t fd64);
    int exist_info(fd64_t);
    int exist(fd64_t fd64);
    int to_fd(fd64_t);
    void fd64_close(fd64_t fd64);
    void reserve(int n);
    u64_t create(int fd);
    fd_manager_t();

   private:
    u64_t counter;
    unordered_map<int, fd64_t> fd_to_fd64_mp;
    unordered_map<fd64_t, int> fd64_to_fd_mp;
    unordered_map<fd64_t, fd_info_t> fd_info_mp;
    int fd_exist(int fd);
    // void remove_fd(int fd);
    // fd64_t fd_to_fd64(int fd);
};

extern fd_manager_t fd_manager;
#endif /* FD_MANAGER_H_ */


================================================
FILE: images/speedtest/111
================================================



================================================
FILE: images/wiki/111
================================================



================================================
FILE: lib/aes-common.h
================================================
/*
 *  this file comes from https://github.com/kokke/tiny-AES128-C
 */

#pragma once

#include <stdint.h>


void AES_ECB_encrypt_buffer(const uint8_t* input, const uint8_t* key, uint8_t *output);
void AES_ECB_decrypt_buffer(const uint8_t* input, const uint8_t* key, uint8_t *output);

void AES_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv);
void AES_CBC_decrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv);


void AES_CFB_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv);
void AES_CFB_decrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv);


================================================
FILE: lib/aes_acc/aesacc.c
================================================
/*
 * This file is adapted from PolarSSL 1.3.19 (GPL)
 */

#include "aesni.h"
#include "aesarm.h"
#include <stdint.h>
#include <string.h>
#include <assert.h>

#if defined(AES256) && (AES256 == 1)
#define AES_KEYSIZE 256
#ifdef HAVE_AMD64
  #define aeshw_setkey_enc aesni_setkey_enc_256
#endif
#elif defined(AES192) && (AES192 == 1)
#define AES_KEYSIZE 192
#ifdef HAVE_AMD64
  #define aeshw_setkey_enc aesni_setkey_enc_192
#endif
#else
#define AES_KEYSIZE 128
#ifdef HAVE_AMD64
  #define aeshw_setkey_enc aesni_setkey_enc_128
#endif
#endif

#define AES_NR ((AES_KEYSIZE >> 5) + 6)
#define AES_RKSIZE      272

#ifdef HAVE_AMD64
#define HAVE_HARDAES 1
#define aeshw_supported aesni_supported
#define aeshw_crypt_ecb aesni_crypt_ecb
#define aeshw_inverse_key(a,b) aesni_inverse_key(a,b,AES_NR)
#endif /* HAVE_AMD64 */

#ifdef HAVE_ARM64
#define HAVE_HARDAES 1
#define aeshw_supported aesarm_supported
#define aeshw_crypt_ecb aesarm_crypt_ecb

#include "aesarm_table.h"

#ifndef GET_UINT32_LE
#define GET_UINT32_LE(n,b,i)                            \
{                                                       \
    (n) = ( (uint32_t) (b)[(i)    ]       )             \
        | ( (uint32_t) (b)[(i) + 1] <<  8 )             \
        | ( (uint32_t) (b)[(i) + 2] << 16 )             \
        | ( (uint32_t) (b)[(i) + 3] << 24 );            \
}
#endif

static void aeshw_setkey_enc(uint8_t *rk, const uint8_t *key)
{
    unsigned int i;
    uint32_t *RK;

    RK = (uint32_t *) rk;

    for( i = 0; i < ( AES_KEYSIZE >> 5 ); i++ )
    {
        GET_UINT32_LE( RK[i], key, i << 2 );
    }

    switch( AES_NR )
    {
        case 10:

            for( i = 0; i < 10; i++, RK += 4 )
            {
                RK[4]  = RK[0] ^ RCON[i] ^
                ( (uint32_t) FSb[ ( RK[3] >>  8 ) & 0xFF ]       ) ^
                ( (uint32_t) FSb[ ( RK[3] >> 16 ) & 0xFF ] <<  8 ) ^
                ( (uint32_t) FSb[ ( RK[3] >> 24 ) & 0xFF ] << 16 ) ^
                ( (uint32_t) FSb[ ( RK[3]       ) & 0xFF ] << 24 );

                RK[5]  = RK[1] ^ RK[4];
                RK[6]  = RK[2] ^ RK[5];
                RK[7]  = RK[3] ^ RK[6];
            }
            break;

        case 12:

            for( i = 0; i < 8; i++, RK += 6 )
            {
                RK[6]  = RK[0] ^ RCON[i] ^
                ( (uint32_t) FSb[ ( RK[5] >>  8 ) & 0xFF ]       ) ^
                ( (uint32_t) FSb[ ( RK[5] >> 16 ) & 0xFF ] <<  8 ) ^
                ( (uint32_t) FSb[ ( RK[5] >> 24 ) & 0xFF ] << 16 ) ^
                ( (uint32_t) FSb[ ( RK[5]       ) & 0xFF ] << 24 );

                RK[7]  = RK[1] ^ RK[6];
                RK[8]  = RK[2] ^ RK[7];
                RK[9]  = RK[3] ^ RK[8];
                RK[10] = RK[4] ^ RK[9];
                RK[11] = RK[5] ^ RK[10];
            }
            break;

        case 14:

            for( i = 0; i < 7; i++, RK += 8 )
            {
                RK[8]  = RK[0] ^ RCON[i] ^
                ( (uint32_t) FSb[ ( RK[7] >>  8 ) & 0xFF ]       ) ^
                ( (uint32_t) FSb[ ( RK[7] >> 16 ) & 0xFF ] <<  8 ) ^
                ( (uint32_t) FSb[ ( RK[7] >> 24 ) & 0xFF ] << 16 ) ^
                ( (uint32_t) FSb[ ( RK[7]       ) & 0xFF ] << 24 );

                RK[9]  = RK[1] ^ RK[8];
                RK[10] = RK[2] ^ RK[9];
                RK[11] = RK[3] ^ RK[10];

                RK[12] = RK[4] ^
                ( (uint32_t) FSb[ ( RK[11]       ) & 0xFF ]       ) ^
                ( (uint32_t) FSb[ ( RK[11] >>  8 ) & 0xFF ] <<  8 ) ^
                ( (uint32_t) FSb[ ( RK[11] >> 16 ) & 0xFF ] << 16 ) ^
                ( (uint32_t) FSb[ ( RK[11] >> 24 ) & 0xFF ] << 24 );

                RK[13] = RK[5] ^ RK[12];
                RK[14] = RK[6] ^ RK[13];
                RK[15] = RK[7] ^ RK[14];
            }
            break;
    }
}

static void aeshw_inverse_key(uint8_t *invkey, const uint8_t *fwdkey)
{
  int i, j;
  uint32_t *RK;
  uint32_t *SK;

  RK = (uint32_t *) invkey;
  SK = ((uint32_t *) fwdkey) + AES_NR * 4;

  *RK++ = *SK++;
  *RK++ = *SK++;
  *RK++ = *SK++;
  *RK++ = *SK++;

  for( i = AES_NR - 1, SK -= 8; i > 0; i--, SK -= 8 )
  {
      for( j = 0; j < 4; j++, SK++ )
      {
          *RK++ = RT0[ FSb[ ( *SK       ) & 0xFF ] ] ^
                  RT1[ FSb[ ( *SK >>  8 ) & 0xFF ] ] ^
                  RT2[ FSb[ ( *SK >> 16 ) & 0xFF ] ] ^
                  RT3[ FSb[ ( *SK >> 24 ) & 0xFF ] ];
      }
  }

  *RK++ = *SK++;
  *RK++ = *SK++;
  *RK++ = *SK++;
  *RK++ = *SK++;
}
#endif /* HAVE_ARM64 */

#ifdef HAVE_HARDAES
static void aeshw_setkey_dec(uint8_t *rk, const uint8_t *key)
{
  uint8_t rk_tmp[AES_RKSIZE];
  aeshw_setkey_enc(rk_tmp, key);
  aeshw_inverse_key(rk, rk_tmp);
}

static void aeshw_encrypt_ecb( int nr,
                               unsigned char *rk,
                               const unsigned char input[16],
                               unsigned char output[16] )
{
  aeshw_crypt_ecb(nr, rk, AES_ENCRYPT, input, output);
}

static void aeshw_decrypt_ecb( int nr,
                               unsigned char *rk,
                               const unsigned char input[16],
                               unsigned char output[16] )
{
  aeshw_crypt_ecb(nr, rk, AES_DECRYPT, input, output);
}
#endif /* HAVE_HARDAES */

/* OpenSSL assembly functions */
#define AES_MAXNR 14
typedef struct {
  uint32_t rd_key[4 * (AES_MAXNR + 1)];
  uint32_t rounds;
} AES_KEY;

#if defined(__amd64__) || defined(__x86_64__) || \
    defined(__aarch64__)
#define AES_set_encrypt_key vpaes_set_encrypt_key
#define AES_set_decrypt_key vpaes_set_decrypt_key
#define AES_encrypt vpaes_encrypt
#define AES_decrypt vpaes_decrypt
#endif /* VPAES for 64-bit Intel and ARM */

#ifdef __cplusplus
extern "C" {
#endif

int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
                        AES_KEY *key);
int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
                        AES_KEY *key);

void AES_encrypt(const unsigned char *in, unsigned char *out,
                 const AES_KEY *key);
void AES_decrypt(const unsigned char *in, unsigned char *out,
                 const AES_KEY *key);

#ifdef __cplusplus
}
#endif

static void aes_encrypt_ecb( int nr,
                             unsigned char *rk,
                             const unsigned char input[16],
                             unsigned char output[16] )
{
  AES_encrypt(input, output, (AES_KEY *) rk);
}

static void aes_decrypt_ecb( int nr,
                             unsigned char *rk,
                             const unsigned char input[16],
                             unsigned char output[16] )
{
  AES_decrypt(input, output, (AES_KEY *) rk);
}

static void aes_setkey_enc(uint8_t *rk, const uint8_t *key)
{
  AES_set_encrypt_key(key, AES_KEYSIZE, (AES_KEY *) rk);
}

static void aes_setkey_dec(uint8_t *rk, const uint8_t *key)
{
  AES_set_decrypt_key(key, AES_KEYSIZE, (AES_KEY *) rk);
}

static void (*encrypt_ecb) ( int nr,
                             unsigned char *rk,
                             const unsigned char input[16],
                             unsigned char output[16] )
  = aes_encrypt_ecb;

static void (*decrypt_ecb) ( int nr,
                             unsigned char *rk,
                             const unsigned char input[16],
                             unsigned char output[16] )
  = aes_decrypt_ecb;

static void (*setkey_enc) (uint8_t *rk, const uint8_t *key)
  = aes_setkey_enc;

static void (*setkey_dec) (uint8_t *rk, const uint8_t *key)
  = aes_setkey_dec;

/*
 * AESNI-CBC buffer encryption/decryption
 */
static void encrypt_cbc( uint8_t* rk,
                         uint32_t length,
                         uint8_t iv[16],
                         const uint8_t *input,
                         uint8_t *output )
{
    int i;
    uint8_t temp[16];

    while( length > 0 )
    {
        for( i = 0; i < 16; i++ )
            output[i] = (uint8_t)( input[i] ^ iv[i] );

        encrypt_ecb( AES_NR, rk, output, output );
        memcpy( iv, output, 16 );

        input  += 16;
        output += 16;
        length -= 16;
    }
}

static void decrypt_cbc( uint8_t* rk,
                         uint32_t length,
                         uint8_t iv[16],
                         const uint8_t *input,
                         uint8_t *output )
{
    int i;
    uint8_t temp[16];

    while( length > 0 )
    {
        memcpy( temp, input, 16 );
        decrypt_ecb( AES_NR, rk, input, output );

        for( i = 0; i < 16; i++ )
            output[i] = (uint8_t)( output[i] ^ iv[i] );

        memcpy( iv, temp, 16 );

        input  += 16;
        output += 16;
        length -= 16;
    }
}

static void aeshw_init(void)
{
#ifdef HAVE_HARDAES
  static int done = 0;
  if (!done) {
    if (aeshw_supported()) {
      encrypt_ecb = aeshw_encrypt_ecb;
      decrypt_ecb = aeshw_decrypt_ecb;
      setkey_enc = aeshw_setkey_enc;
      setkey_dec = aeshw_setkey_dec;
    }
    done = 1;
  }
#endif
}

int AES_support_hwaccel(void)
{
#ifdef HAVE_HARDAES
  return aeshw_supported();
#else
  return 0;
#endif
}

void AES_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv)
{
  uint8_t iv_tmp[16];
  static uint8_t rk[AES_RKSIZE];

  assert(iv!=NULL);
  aeshw_init();
  memcpy(iv_tmp, iv, 16);
  if(key!= NULL)
	  setkey_enc(rk, key);
  encrypt_cbc(rk, length, iv_tmp, input, output);
}

void AES_CBC_decrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv)
{
  uint8_t iv_tmp[16];
  static uint8_t rk[AES_RKSIZE];

  assert(iv!=NULL);
  aeshw_init();
  memcpy(iv_tmp, iv, 16);
  if(key!= NULL)
  {
	  setkey_dec(rk, key);
  }
  decrypt_cbc(rk, length, iv_tmp, input, output);
}

void AES_ECB_encrypt_buffer(const uint8_t* input, const uint8_t* key, uint8_t* output)
{
  static uint8_t rk[AES_RKSIZE];

  aeshw_init();
  if(key!=NULL)
    setkey_enc(rk, key);
  encrypt_ecb(AES_NR, rk, input, output);
}

void AES_ECB_decrypt_buffer(const uint8_t* input, const uint8_t* key, uint8_t *output)
{
  static uint8_t rk[AES_RKSIZE];

  aeshw_init();
  if(key!=NULL)
    setkey_dec(rk, key);
  decrypt_ecb(AES_NR, rk, input, output);
}

static void encrypt_cfb( uint8_t* rk,
                         uint32_t length,size_t *iv_off,
                         uint8_t iv[16],
                         const uint8_t *input,
                         uint8_t *output )
{
    int c;
    size_t n = *iv_off;
    while( length-- )
    {
        if( n == 0 )
        	encrypt_ecb( AES_NR, rk, iv, iv );

        iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ );

        n = ( n + 1 ) & 0x0F;
    }

    *iv_off = n;
}

static void decrypt_cfb( uint8_t* rk,
                         uint32_t length,size_t *iv_off,
                         uint8_t iv[16],
                         const uint8_t *input,
                         uint8_t *output )
{
    int c;
    size_t n = *iv_off;
    while( length-- )
    {
        if( n == 0 )
        	encrypt_ecb( AES_NR, rk, iv, iv );

        c = *input++;
        *output++ = (unsigned char)( c ^ iv[n] );
        iv[n] = (unsigned char) c;

        n = ( n + 1 ) & 0x0F;
    }

    *iv_off = n;
}

void AES_CFB_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv)
{
  uint8_t iv_tmp[16];
  static uint8_t rk[AES_RKSIZE];

  assert(iv!=NULL);
  aeshw_init();
  memcpy(iv_tmp, iv, 16);
  if(key!= NULL)
	  setkey_enc(rk, key);
  size_t offset=0;
  encrypt_cfb(rk, length,&offset, iv_tmp, input, output);
}

void AES_CFB_decrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv)
{
  uint8_t iv_tmp[16];
  static uint8_t rk[AES_RKSIZE];

  assert(iv!=NULL);
  aeshw_init();
  memcpy(iv_tmp, iv, 16);
  if(key!= NULL)
  {
	  setkey_enc(rk, key);//its enc again,not typo
  }
  size_t offset=0;
  decrypt_cfb(rk, length,&offset, iv_tmp, input, output);
}



================================================
FILE: lib/aes_acc/aesarm.c
================================================
/*
 * This file is adapted from https://github.com/CriticalBlue/mbedtls
 */

/*
 *  ARMv8-A Cryptography Extension AES support functions
 *
 *  Copyright (C) 2016, CriticalBlue Limited, All Rights Reserved
 *  SPDX-License-Identifier: Apache-2.0
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may
 *  not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  This file is part of mbed TLS (https://tls.mbed.org)
 */

#include "aesarm.h"

#if defined(HAVE_ARM64)

#include <sys/auxv.h>
#include <asm/hwcap.h>
#include <arm_neon.h>

/*
 * ARMv8a Crypto Extension support detection routine
 */
int aesarm_supported( void )
{
    static int done = 0;
    static unsigned int c = 0;

    if ( ! done )
    {
        c = getauxval(AT_HWCAP);
        done = 1;
    }

    return ( c & HWCAP_AES ) != 0;
}

/*
 * ARMv8a AES-ECB block en(de)cryption
 */
void aesarm_crypt_ecb( int nr,
                       unsigned char *rk,
                       int mode,
                       const unsigned char input[16],
                       unsigned char output[16] )
{
    int i;
    uint8x16_t state_vec, roundkey_vec;
    uint8_t *RK = (uint8_t *) rk;

    // Load input and round key into into their vectors
    state_vec = vld1q_u8( input );

    if ( mode == AES_ENCRYPT )
    {
        // Initial AddRoundKey is in the loop due to AES instruction always doing AddRoundKey first
        for( i = 0; i < nr - 1; i++ )
        {
            // Load Round Key
            roundkey_vec = vld1q_u8( RK );
            // Forward (AESE) round (AddRoundKey, SubBytes and ShiftRows)
            state_vec = vaeseq_u8( state_vec, roundkey_vec );
            // Mix Columns (AESMC)
            state_vec = vaesmcq_u8( state_vec );
            // Move pointer ready to load next round key
            RK += 16;
        }

        // Final Forward (AESE) round (AddRoundKey, SubBytes and ShiftRows). No Mix columns
        roundkey_vec = vld1q_u8( RK ); /* RK already moved in loop */
        state_vec = vaeseq_u8( state_vec, roundkey_vec );
    }
    else
    {
        // Initial AddRoundKey is in the loop due to AES instruction always doing AddRoundKey first
        for( i = 0; i < nr - 1; i++ )
        {
            // Load Round Key
            roundkey_vec = vld1q_u8( RK );
            // Reverse (AESD) round (AddRoundKey, SubBytes and ShiftRows)
            state_vec = vaesdq_u8( state_vec, roundkey_vec );
            // Inverse Mix Columns (AESIMC)
            state_vec = vaesimcq_u8( state_vec );
            // Move pointer ready to load next round key
            RK += 16;
        }

        // Final Reverse (AESD) round (AddRoundKey, SubBytes and ShiftRows). No Mix columns
        roundkey_vec = vld1q_u8( RK ); /* RK already moved in loop */
        state_vec = vaesdq_u8( state_vec, roundkey_vec );
    }

    // Manually apply final Add RoundKey step (EOR)
    RK += 16;
    roundkey_vec = vld1q_u8( RK );
    state_vec = veorq_u8( state_vec, roundkey_vec );

    // Write results back to output array
    vst1q_u8( output, state_vec );
}

#endif /* HAVE_ARM64 */


================================================
FILE: lib/aes_acc/aesarm.h
================================================
/*
 * This file is adapted from https://github.com/CriticalBlue/mbedtls
 */

/**
 * \file aes_armv8a_ce.h
 *
 * \brief AES support functions using the ARMv8-A Cryptography Extension for
 * hardware acceleration on some ARM processors.
 *
 *  Copyright (C) 2016, CriticalBlue Limited, All Rights Reserved
 *  SPDX-License-Identifier: Apache-2.0
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may
 *  not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  This file is part of mbed TLS (https://tls.mbed.org)
 */

#ifndef UDP2RAW_AESARM_H_
#define UDP2RAW_AESARM_H_

#ifndef AES_ENCRYPT
#define AES_ENCRYPT     1
#endif

#ifndef AES_DECRYPT
#define AES_DECRYPT     0
#endif

#if defined(__GNUC__) && \
    __ARM_ARCH >= 8 && \
    __ARM_ARCH_PROFILE == 'A' && \
    defined(__aarch64__) &&  \
    defined(__ARM_FEATURE_CRYPTO) && \
    defined(__linux__) && \
    !defined(NO_AESACC)
#define HAVE_ARM64
#endif

#if defined(HAVE_ARM64)

#ifdef __cplusplus
extern "C" {
#endif

/**
 * \brief          ARMv8-A features detection routine
 *
 * \return         1 if the CPU has support for the feature, 0 otherwise
 */
int aesarm_supported( void );

/**
 * \brief          AES ARMv8-A Cryptography Extension AES-ECB block en(de)cryption
 *
 * \param nr       number of rounds
 * \param rk       AES round keys
 * \param mode     AESARM_ENCRYPT or AESARM_DECRYPT
 * \param input    16-byte input block
 * \param output   16-byte output block
 */
void aesarm_crypt_ecb( int nr,
                       unsigned char *rk,
                       int mode,
                       const unsigned char input[16],
                       unsigned char output[16] );

#ifdef __cplusplus
}
#endif 

#endif /* HAVE_ARM64 */

#endif /* _AESARM_H_ */


================================================
FILE: lib/aes_acc/aesarm_table.h
================================================
/*
 * This file is adapted from PolarSSL 1.3.19 (GPL)
 */

/*
 * Forward S-box
 */
static const unsigned char FSb[256] =
{
    0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5,
    0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
    0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0,
    0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
    0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC,
    0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
    0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A,
    0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
    0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0,
    0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
    0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B,
    0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
    0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85,
    0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
    0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,
    0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
    0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17,
    0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
    0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88,
    0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
    0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C,
    0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
    0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9,
    0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
    0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6,
    0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
    0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E,
    0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
    0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94,
    0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
    0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68,
    0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
};

/*
 * Round constants
 */
static const uint32_t RCON[10] =
{
    0x00000001, 0x00000002, 0x00000004, 0x00000008,
    0x00000010, 0x00000020, 0x00000040, 0x00000080,
    0x0000001B, 0x00000036
};

/*
 * Reverse tables
 */
#define RT \
\
    V(50,A7,F4,51), V(53,65,41,7E), V(C3,A4,17,1A), V(96,5E,27,3A), \
    V(CB,6B,AB,3B), V(F1,45,9D,1F), V(AB,58,FA,AC), V(93,03,E3,4B), \
    V(55,FA,30,20), V(F6,6D,76,AD), V(91,76,CC,88), V(25,4C,02,F5), \
    V(FC,D7,E5,4F), V(D7,CB,2A,C5), V(80,44,35,26), V(8F,A3,62,B5), \
    V(49,5A,B1,DE), V(67,1B,BA,25), V(98,0E,EA,45), V(E1,C0,FE,5D), \
    V(02,75,2F,C3), V(12,F0,4C,81), V(A3,97,46,8D), V(C6,F9,D3,6B), \
    V(E7,5F,8F,03), V(95,9C,92,15), V(EB,7A,6D,BF), V(DA,59,52,95), \
    V(2D,83,BE,D4), V(D3,21,74,58), V(29,69,E0,49), V(44,C8,C9,8E), \
    V(6A,89,C2,75), V(78,79,8E,F4), V(6B,3E,58,99), V(DD,71,B9,27), \
    V(B6,4F,E1,BE), V(17,AD,88,F0), V(66,AC,20,C9), V(B4,3A,CE,7D), \
    V(18,4A,DF,63), V(82,31,1A,E5), V(60,33,51,97), V(45,7F,53,62), \
    V(E0,77,64,B1), V(84,AE,6B,BB), V(1C,A0,81,FE), V(94,2B,08,F9), \
    V(58,68,48,70), V(19,FD,45,8F), V(87,6C,DE,94), V(B7,F8,7B,52), \
    V(23,D3,73,AB), V(E2,02,4B,72), V(57,8F,1F,E3), V(2A,AB,55,66), \
    V(07,28,EB,B2), V(03,C2,B5,2F), V(9A,7B,C5,86), V(A5,08,37,D3), \
    V(F2,87,28,30), V(B2,A5,BF,23), V(BA,6A,03,02), V(5C,82,16,ED), \
    V(2B,1C,CF,8A), V(92,B4,79,A7), V(F0,F2,07,F3), V(A1,E2,69,4E), \
    V(CD,F4,DA,65), V(D5,BE,05,06), V(1F,62,34,D1), V(8A,FE,A6,C4), \
    V(9D,53,2E,34), V(A0,55,F3,A2), V(32,E1,8A,05), V(75,EB,F6,A4), \
    V(39,EC,83,0B), V(AA,EF,60,40), V(06,9F,71,5E), V(51,10,6E,BD), \
    V(F9,8A,21,3E), V(3D,06,DD,96), V(AE,05,3E,DD), V(46,BD,E6,4D), \
    V(B5,8D,54,91), V(05,5D,C4,71), V(6F,D4,06,04), V(FF,15,50,60), \
    V(24,FB,98,19), V(97,E9,BD,D6), V(CC,43,40,89), V(77,9E,D9,67), \
    V(BD,42,E8,B0), V(88,8B,89,07), V(38,5B,19,E7), V(DB,EE,C8,79), \
    V(47,0A,7C,A1), V(E9,0F,42,7C), V(C9,1E,84,F8), V(00,00,00,00), \
    V(83,86,80,09), V(48,ED,2B,32), V(AC,70,11,1E), V(4E,72,5A,6C), \
    V(FB,FF,0E,FD), V(56,38,85,0F), V(1E,D5,AE,3D), V(27,39,2D,36), \
    V(64,D9,0F,0A), V(21,A6,5C,68), V(D1,54,5B,9B), V(3A,2E,36,24), \
    V(B1,67,0A,0C), V(0F,E7,57,93), V(D2,96,EE,B4), V(9E,91,9B,1B), \
    V(4F,C5,C0,80), V(A2,20,DC,61), V(69,4B,77,5A), V(16,1A,12,1C), \
    V(0A,BA,93,E2), V(E5,2A,A0,C0), V(43,E0,22,3C), V(1D,17,1B,12), \
    V(0B,0D,09,0E), V(AD,C7,8B,F2), V(B9,A8,B6,2D), V(C8,A9,1E,14), \
    V(85,19,F1,57), V(4C,07,75,AF), V(BB,DD,99,EE), V(FD,60,7F,A3), \
    V(9F,26,01,F7), V(BC,F5,72,5C), V(C5,3B,66,44), V(34,7E,FB,5B), \
    V(76,29,43,8B), V(DC,C6,23,CB), V(68,FC,ED,B6), V(63,F1,E4,B8), \
    V(CA,DC,31,D7), V(10,85,63,42), V(40,22,97,13), V(20,11,C6,84), \
    V(7D,24,4A,85), V(F8,3D,BB,D2), V(11,32,F9,AE), V(6D,A1,29,C7), \
    V(4B,2F,9E,1D), V(F3,30,B2,DC), V(EC,52,86,0D), V(D0,E3,C1,77), \
    V(6C,16,B3,2B), V(99,B9,70,A9), V(FA,48,94,11), V(22,64,E9,47), \
    V(C4,8C,FC,A8), V(1A,3F,F0,A0), V(D8,2C,7D,56), V(EF,90,33,22), \
    V(C7,4E,49,87), V(C1,D1,38,D9), V(FE,A2,CA,8C), V(36,0B,D4,98), \
    V(CF,81,F5,A6), V(28,DE,7A,A5), V(26,8E,B7,DA), V(A4,BF,AD,3F), \
    V(E4,9D,3A,2C), V(0D,92,78,50), V(9B,CC,5F,6A), V(62,46,7E,54), \
    V(C2,13,8D,F6), V(E8,B8,D8,90), V(5E,F7,39,2E), V(F5,AF,C3,82), \
    V(BE,80,5D,9F), V(7C,93,D0,69), V(A9,2D,D5,6F), V(B3,12,25,CF), \
    V(3B,99,AC,C8), V(A7,7D,18,10), V(6E,63,9C,E8), V(7B,BB,3B,DB), \
    V(09,78,26,CD), V(F4,18,59,6E), V(01,B7,9A,EC), V(A8,9A,4F,83), \
    V(65,6E,95,E6), V(7E,E6,FF,AA), V(08,CF,BC,21), V(E6,E8,15,EF), \
    V(D9,9B,E7,BA), V(CE,36,6F,4A), V(D4,09,9F,EA), V(D6,7C,B0,29), \
    V(AF,B2,A4,31), V(31,23,3F,2A), V(30,94,A5,C6), V(C0,66,A2,35), \
    V(37,BC,4E,74), V(A6,CA,82,FC), V(B0,D0,90,E0), V(15,D8,A7,33), \
    V(4A,98,04,F1), V(F7,DA,EC,41), V(0E,50,CD,7F), V(2F,F6,91,17), \
    V(8D,D6,4D,76), V(4D,B0,EF,43), V(54,4D,AA,CC), V(DF,04,96,E4), \
    V(E3,B5,D1,9E), V(1B,88,6A,4C), V(B8,1F,2C,C1), V(7F,51,65,46), \
    V(04,EA,5E,9D), V(5D,35,8C,01), V(73,74,87,FA), V(2E,41,0B,FB), \
    V(5A,1D,67,B3), V(52,D2,DB,92), V(33,56,10,E9), V(13,47,D6,6D), \
    V(8C,61,D7,9A), V(7A,0C,A1,37), V(8E,14,F8,59), V(89,3C,13,EB), \
    V(EE,27,A9,CE), V(35,C9,61,B7), V(ED,E5,1C,E1), V(3C,B1,47,7A), \
    V(59,DF,D2,9C), V(3F,73,F2,55), V(79,CE,14,18), V(BF,37,C7,73), \
    V(EA,CD,F7,53), V(5B,AA,FD,5F), V(14,6F,3D,DF), V(86,DB,44,78), \
    V(81,F3,AF,CA), V(3E,C4,68,B9), V(2C,34,24,38), V(5F,40,A3,C2), \
    V(72,C3,1D,16), V(0C,25,E2,BC), V(8B,49,3C,28), V(41,95,0D,FF), \
    V(71,01,A8,39), V(DE,B3,0C,08), V(9C,E4,B4,D8), V(90,C1,56,64), \
    V(61,84,CB,7B), V(70,B6,32,D5), V(74,5C,6C,48), V(42,57,B8,D0)

#define V(a,b,c,d) 0x##a##b##c##d
static const uint32_t RT0[256] = { RT };
#undef V

#define V(a,b,c,d) 0x##b##c##d##a
static const uint32_t RT1[256] = { RT };
#undef V

#define V(a,b,c,d) 0x##c##d##a#
Download .txt
gitextract_9hxphtn3/

├── .clang-format
├── .gitattributes
├── CMakeLists.txt
├── ISSUE_TEMPLATE.md
├── LICENSE.md
├── README.md
├── client.cpp
├── common.cpp
├── common.h
├── connection.cpp
├── connection.h
├── doc/
│   ├── README.zh-cn.md
│   ├── android_guide.md
│   ├── build_guide.md
│   ├── build_guide.zh-cn.md
│   ├── finalspeed_step_by_step/
│   │   └── 11
│   ├── finalspeed_step_by_step.md
│   ├── kcptun_step_by_step.md
│   └── openvpn_guide.md
├── encrypt.cpp
├── encrypt.h
├── example.conf
├── fd_manager.cpp
├── fd_manager.h
├── images/
│   ├── speedtest/
│   │   └── 111
│   └── wiki/
│       └── 111
├── lib/
│   ├── aes-common.h
│   ├── aes_acc/
│   │   ├── aesacc.c
│   │   ├── aesarm.c
│   │   ├── aesarm.h
│   │   ├── aesarm_table.h
│   │   ├── aesni.c
│   │   ├── aesni.h
│   │   └── asm/
│   │       ├── arm.S
│   │       ├── arm64.S
│   │       ├── arm_arch.h
│   │       ├── mips.S
│   │       ├── mips_be.S
│   │       ├── x64.S
│   │       └── x86.S
│   ├── aes_faster_c/
│   │   ├── aes.cpp
│   │   ├── aes.h
│   │   └── wrapper.cpp
│   ├── md5.cpp
│   ├── md5.h
│   ├── pbkdf2-sha1.cpp
│   ├── pbkdf2-sha1.h
│   ├── pbkdf2-sha256.cpp
│   └── pbkdf2-sha256.h
├── libev/
│   ├── CVS/
│   │   ├── Entries
│   │   ├── Repository
│   │   └── Root
│   ├── Changes
│   ├── LICENSE
│   ├── Makefile.am
│   ├── README
│   ├── README.embed
│   ├── Symbols.ev
│   ├── Symbols.event
│   ├── autogen.sh
│   ├── configure.ac
│   ├── ev++.h
│   ├── ev.3
│   ├── ev.c
│   ├── ev.h
│   ├── ev.pod
│   ├── ev_epoll.c
│   ├── ev_kqueue.c
│   ├── ev_poll.c
│   ├── ev_port.c
│   ├── ev_select.c
│   ├── ev_vars.h
│   ├── ev_win32.c
│   ├── ev_wrap.h
│   ├── event.c
│   ├── event.h
│   ├── event_compat.h
│   ├── import_libevent
│   ├── libev.m4
│   ├── update_ev_c
│   ├── update_ev_wrap
│   └── update_symbols
├── log.cpp
├── log.h
├── main.cpp
├── makefile
├── misc.cpp
├── misc.h
├── my_ev.cpp
├── my_ev.h
├── my_ev_common.h
├── network.cpp
├── network.h
├── pcap_wrapper.cpp
├── pcap_wrapper.h
├── server.cpp
└── third-party/
    ├── luci-app-udp2raw/
    │   └── moved_to_new_repo
    ├── udp2raw-cmake-makefile/
    │   └── CMakeLists.txt
    └── udp2raw-openwrt-makefile/
        └── moved_to_new_repo
Download .txt
SYMBOL INDEX (833 symbols across 40 files)

FILE: client.cpp
  function client_on_timer (line 22) | int client_on_timer(conn_info_t &conn_info)  // for client. called when ...
  function client_on_raw_recv_hs2_or_ready (line 312) | int client_on_raw_recv_hs2_or_ready(conn_info_t &conn_info, char type, c...
  function client_on_raw_recv (line 372) | int client_on_raw_recv(conn_info_t &conn_info)  // called when raw fd re...
  function client_on_udp_recv (line 501) | int client_on_udp_recv(conn_info_t &conn_info) {
  function udp_accept_cb (line 545) | void udp_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int reve...
  function raw_recv_cb (line 549) | void raw_recv_cb(struct ev_loop *loop, struct ev_io *watcher, int revent...
  function async_cb (line 555) | void async_cb(struct ev_loop *loop, struct ev_async *watcher, int revent...
  function clear_timer_cb (line 613) | void clear_timer_cb(struct ev_loop *loop, struct ev_timer *watcher, int ...
  function fifo_cb (line 617) | void fifo_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) {
  function client_event_loop (line 640) | int client_event_loop() {

FILE: common.cpp
  type sockaddr (line 204) | struct sockaddr
  function init_ws (line 284) | int init_ws() {
  function inet_pton (line 333) | int inet_pton(int af, const char *src, void *dst) {
  type sockaddr_storage (line 357) | struct sockaddr_storage
  type sockaddr_in (line 365) | struct sockaddr_in
  type in_addr (line 365) | struct in_addr
  type sockaddr_in6 (line 368) | struct sockaddr_in6
  type in6_addr (line 368) | struct in6_addr
  type sockaddr (line 374) | struct sockaddr
  function get_sock_errno (line 393) | int get_sock_errno() {
  function get_sock_errno (line 402) | int get_sock_errno() {
  function u64_t (line 407) | u64_t get_current_time_us() {
  function u64_t (line 425) | u64_t get_current_time() {
  function u64_t (line 429) | u64_t pack_u64(u32_t a, u32_t b) {
  function u32_t (line 435) | u32_t get_u64_h(u64_t a) {
  function u32_t (line 438) | u32_t get_u64_l(u64_t a) {
  type random_fd_t (line 462) | struct random_fd_t {
    method random_fd_t (line 464) | random_fd_t() {
    method get_fd (line 473) | int get_fd() {
  type my_random_t (line 478) | struct my_random_t {
    method my_random_t (line 486) | my_random_t() {
    method u64_t (line 495) | u64_t gen64() {
    method u32_t (line 498) | u32_t gen32() {
    method gen8 (line 502) | unsigned char gen8() {
  function u64_t (line 523) | u64_t get_true_random_number_64() {
  function u32_t (line 536) | u32_t get_true_random_number() {
  function u32_t (line 549) | u32_t get_true_random_number_nz()  // nz for non-zero
  function is_big_endian (line 558) | inline int is_big_endian() {
  function u64_t (line 562) | u64_t ntoh64(u64_t a) {
  function u64_t (line 572) | u64_t hton64(u64_t a) {
  function write_u16 (line 576) | void write_u16(char *p, u16_t w) {
  function u16_t (line 580) | u16_t read_u16(char *p) {
  function write_u32 (line 587) | void write_u32(char *p, u32_t l) {
  function u32_t (line 593) | u32_t read_u32(char *p) {
  function write_u64 (line 602) | void write_u64(char *s, u64_t a) {
  function u64_t (line 605) | u64_t read_u64(char *s) {
  function setnonblocking (line 610) | void setnonblocking(int sock) {
  function csum (line 639) | unsigned short csum(const unsigned short *ptr, int nbytes) {  // works b...
  function csum_with_header (line 662) | unsigned short csum_with_header(char *header, int hlen, const unsigned s...
  function set_buf_size (line 693) | int set_buf_size(int fd, int socket_buf_size) {
  function numbers_to_char (line 724) | int numbers_to_char(my_id_t id1, my_id_t id2, my_id_t id3, char *&data, ...
  function char_to_numbers (line 740) | int char_to_numbers(const char *data, int len, my_id_t &id1, my_id_t &id...
  function hex_to_u32 (line 753) | int hex_to_u32(const string &a, u32_t &output) {
  function hex_to_u32_with_endian (line 763) | int hex_to_u32_with_endian(const string &a, u32_t &output) {
  function larger_than_u32 (line 774) | bool larger_than_u32(u32_t a, u32_t b) {
  function larger_than_u16 (line 806) | bool larger_than_u16(uint16_t a, uint16_t b) {
  function myexit (line 837) | void myexit(int a) {
  function string_to_vec (line 853) | vector<string> string_to_vec(const char *s, const char *sp) {
  function string_to_vec2 (line 870) | vector<vector<string> > string_to_vec2(const char *s) {
  function read_file (line 880) | int read_file(const char *file, string &output) {
  function run_command (line 908) | int run_command(string command0, char *&output, int flag) {
  function string (line 1008) | string trim(const string &str, char c) {
  function parse_conf_line (line 1017) | vector<string> parse_conf_line(const string &s0) {
  function create_fifo (line 1067) | int create_fifo(char *file) {
  function print_binary_chars (line 1119) | void print_binary_chars(const char *a, int len) {
  function u32_t (line 1127) | u32_t djb2(unsigned char *str, int len) {
  function u32_t (line 1139) | u32_t sdbm(unsigned char *str, int len) {

FILE: common.h
  type u_int8_t (line 70) | typedef unsigned char u_int8_t;
  type u_int16_t (line 71) | typedef unsigned short u_int16_t;
  type u_int32_t (line 72) | typedef unsigned int u_int32_t;
  type socklen_t (line 73) | typedef int socklen_t;
  type SOCKET (line 129) | typedef SOCKET my_fd_t;
  function sock_close (line 130) | inline int sock_close(my_fd_t fd) {
  type my_fd_t (line 134) | typedef int my_fd_t;
  function sock_close (line 135) | inline int sock_close(my_fd_t fd) {
  type u64_t (line 141) | typedef unsigned long long u64_t;
  type i64_t (line 142) | typedef long long i64_t;
  type u32_t (line 144) | typedef unsigned int u32_t;
  type i32_t (line 145) | typedef int i32_t;
  type u16_t (line 147) | typedef unsigned short u16_t;
  type i16_t (line 148) | typedef short i16_t;
  type u32_t (line 150) | typedef u32_t my_id_t;
  type u64_t (line 152) | typedef u64_t iv_t;
  type u64_t (line 154) | typedef u64_t padding_t;
  type u64_t (line 156) | typedef u64_t anti_replay_seq_t;
  type u64_t (line 158) | typedef u64_t my_time_t;
  type u64_t (line 176) | typedef u64_t fd64_t;
  type address_t (line 181) | struct address_t  // TODO scope id
  function clear (line 199) | void clear() {
  function from_ip_port (line 202) | int from_ip_port(u32_t ip, int port) {
  function from_ip_port_new (line 210) | int from_ip_port_new(int type, void *ip, int port) {
  function u32_t (line 233) | inline u32_t get_type() {
  function u32_t (line 239) | inline u32_t get_len() {
  function u32_t (line 252) | inline u32_t get_port() {
  function set_port (line 265) | inline void set_port(int port) {
  function namespace (line 290) | namespace std {
  type not_copy_able_t (line 314) | struct not_copy_able_t {
  function empty (line 337) | struct queue_t {
  function full (line 352) | int full() {
  function peek_front (line 358) | void peek_front(char *&p, int &len) {
  function pop_front (line 363) | void pop_front() {
  function push_back (line 368) | void push_back(char *p, int len) {
  type lru_pair_t (line 445) | struct lru_pair_t {
  function update (line 453) | int update(key_t key) {
  function new_key (line 470) | int new_key(key_t key) {
  function size (line 485) | int size() {
  function empty (line 488) | int empty() {
  function clear (line 491) | void clear() {
  function my_time_t (line 495) | my_time_t ts_of(key_t key) {
  function my_time_t (line 500) | my_time_t peek_back(key_t &key) {
  function erase (line 507) | void erase(key_t key) {

FILE: connection.cpp
  function anti_replay_seq_t (line 18) | anti_replay_seq_t anti_replay_t::get_new_seq_for_send() {
  function conn_info_t (line 116) | conn_info_t &conn_info_t::operator=(const conn_info_t &b) {
  function conn_info_t (line 172) | conn_info_t *&conn_manager_t::find_insert_p(address_t addr)  // be aware...
  function conn_info_t (line 187) | conn_info_t &conn_manager_t::find_insert(address_t addr)  // be aware,th...
  function send_bare (line 288) | int send_bare(raw_info_t &raw_info, const char *data, int len)  // send ...
  function reserved_parse_bare (line 318) | int reserved_parse_bare(const char *input, int input_len, char *&data, i...
  function recv_bare (line 343) | int recv_bare(raw_info_t &raw_info, char *&data, int &len)  // recv func...
  function send_handshake (line 367) | int send_handshake(raw_info_t &raw_info, my_id_t id1, my_id_t id2, my_id...
  function send_safer (line 393) | int send_safer(conn_info_t &conn_info, char type, const char *data, int ...
  function send_data_safer (line 449) | int send_data_safer(conn_info_t &conn_info, const char *data, int len, u...
  function reserved_parse_safer (line 464) | int reserved_parse_safer(conn_info_t &conn_info, const char *input, int ...
  function recv_safer_notused (line 538) | int recv_safer_notused(conn_info_t &conn_info, char &type, char *&data, ...
  function recv_safer_multi (line 552) | int recv_safer_multi(conn_info_t &conn_info, vector<char> &type_arr, vec...
  function server_clear_function (line 623) | void server_clear_function(u64_t u64)  // used in conv_manager in server...

FILE: connection.h
  type anti_replay_t (line 21) | struct anti_replay_t  // its for anti replay attack,similar to openvpn/i...
  function get_size (line 61) | int get_size() {
  function reserve (line 64) | void reserve() {
  function clear (line 71) | void clear() {
  function u32_t (line 88) | u32_t get_new_conv() {
  function is_conv_used (line 95) | int is_conv_used(u32_t conv) {
  function is_data_used (line 98) | int is_data_used(T data) {
  function u32_t (line 101) | u32_t find_conv_by_data(T data) {
  function T (line 104) | T find_data_by_conv(u32_t conv) {
  function update_active_time (line 107) | int update_active_time(u32_t conv) {
  function insert_conv (line 112) | int insert_conv(u32_t conv, T data) {
  function erase_conv (line 119) | int erase_conv(u32_t conv) {
  function clear_inactive0 (line 138) | int clear_inactive0(char *info) {
  function not_copy_able_t (line 191) | struct blob_t : not_copy_able_t  // used in conn_info_t.
  type conn_info_t (line 218) | struct conn_info_t  // stores info for a raw connection.for client ,ther...
  type conn_manager_t (line 259) | struct conn_manager_t  // manager for connections. for client,we dont ne...

FILE: encrypt.cpp
  function my_init_keys (line 55) | int my_init_keys(const char *user_passwd, int is_client) {
  function crc32h (line 115) | unsigned int crc32h(unsigned char *message, int len) {
  function simple_hash (line 149) | void simple_hash(unsigned char *str, int len, unsigned char res[8])  // ...
  function auth_md5_cal (line 167) | int auth_md5_cal(const char *data, char *output, int &len) {
  function auth_hmac_sha1_cal (line 174) | int auth_hmac_sha1_cal(const char *data, char *output, int &len) {
  function auth_hmac_sha1_verify (line 183) | int auth_hmac_sha1_verify(const char *data, int &len) {
  function auth_crc32_cal (line 201) | int auth_crc32_cal(const char *data, char *output, int &len) {
  function auth_simple_cal (line 210) | int auth_simple_cal(const char *data, char *output, int &len) {
  function auth_simple_verify (line 217) | int auth_simple_verify(const char *data, int &len) {
  function auth_none_cal (line 227) | int auth_none_cal(const char *data, char *output, int &len) {
  function auth_md5_verify (line 231) | int auth_md5_verify(const char *data, int &len) {
  function auth_none_verify (line 247) | int auth_none_verify(const char *data, int &len) {
  function cipher_xor_encrypt (line 251) | int cipher_xor_encrypt(const char *data, char *output, int &len, char *k...
  function cipher_xor_decrypt (line 259) | int cipher_xor_decrypt(const char *data, char *output, int &len, char *k...
  function padding (line 273) | int padding(char *data, int &data_len, int padding_num) {
  function de_padding (line 284) | int de_padding(const char *data, int &data_len, int padding_num) {
  function aes_ecb_encrypt (line 293) | void aes_ecb_encrypt(const char *data, char *output) {
  function aes_ecb_encrypt1 (line 304) | void aes_ecb_encrypt1(char *data) {
  function aes_ecb_decrypt (line 309) | void aes_ecb_decrypt(const char *data, char *output) {
  function aes_ecb_decrypt1 (line 320) | void aes_ecb_decrypt1(char *data) {
  function cipher_aes128cbc_encrypt (line 325) | int cipher_aes128cbc_encrypt(const char *data, char *output, int &len, c...
  function cipher_aes128cfb_encrypt (line 343) | int cipher_aes128cfb_encrypt(const char *data, char *output, int &len, c...
  function auth_crc32_verify (line 362) | int auth_crc32_verify(const char *data, int &len) {
  function cipher_none_encrypt (line 377) | int cipher_none_encrypt(const char *data, char *output, int &len, char *...
  function cipher_aes128cbc_decrypt (line 381) | int cipher_aes128cbc_decrypt(const char *data, char *output, int &len, c...
  function cipher_aes128cfb_decrypt (line 397) | int cipher_aes128cfb_decrypt(const char *data, char *output, int &len, c...
  function cipher_none_decrypt (line 416) | int cipher_none_decrypt(const char *data, char *output, int &len, char *...
  function auth_cal (line 421) | int auth_cal(const char *data, char *output, int &len) {
  function auth_verify (line 440) | int auth_verify(const char *data, int &len) {
  function cipher_encrypt (line 459) | int cipher_encrypt(const char *data, char *output, int &len, char *key) {
  function cipher_decrypt (line 476) | int cipher_decrypt(const char *data, char *output, int &len, char *key) {
  function encrypt_AE (line 494) | int encrypt_AE(const char *data, char *output, int &len /*,char * key*/) {
  function decrypt_AE (line 515) | int decrypt_AE(const char *data, char *output, int &len /*,char * key*/) {
  function my_encrypt (line 531) | int my_encrypt(const char *data, char *output, int &len /*,char * key*/) {
  function my_decrypt (line 558) | int my_decrypt(const char *data, char *output, int &len /*,char * key*/) {
  function encrypt_AEAD (line 580) | int encrypt_AEAD(uint8_t *data, uint8_t *output, int &len, uint8_t *key,...
  function decrypt_AEAD (line 585) | int decrypt_AEAD(uint8_t *data, uint8_t *output, int &len, uint8_t *key,...

FILE: encrypt.h
  type auth_mode_t (line 21) | enum auth_mode_t { auth_none = 0,
  type cipher_mode_t (line 28) | enum cipher_mode_t { cipher_none = 0,

FILE: fd_manager.cpp
  function u64_t (line 35) | u64_t fd_manager_t::create(int fd) {
  function fd_info_t (line 47) | fd_info_t& fd_manager_t::get_info(fd64_t fd64) {

FILE: fd_manager.h
  type fd_info_t (line 15) | struct fd_info_t {
  type fd_manager_t (line 20) | struct fd_manager_t  // conver fd to a uniq 64bit number,avoid fd value ...

FILE: lib/aes_acc/aesacc.c
  function aeshw_setkey_enc (line 55) | static void aeshw_setkey_enc(uint8_t *rk, const uint8_t *key)
  function aeshw_inverse_key (line 131) | static void aeshw_inverse_key(uint8_t *invkey, const uint8_t *fwdkey)
  function aeshw_setkey_dec (line 164) | static void aeshw_setkey_dec(uint8_t *rk, const uint8_t *key)
  function aeshw_encrypt_ecb (line 171) | static void aeshw_encrypt_ecb( int nr,
  function aeshw_decrypt_ecb (line 179) | static void aeshw_decrypt_ecb( int nr,
  type AES_KEY (line 190) | typedef struct {
  function aes_encrypt_ecb (line 221) | static void aes_encrypt_ecb( int nr,
  function aes_decrypt_ecb (line 229) | static void aes_decrypt_ecb( int nr,
  function aes_setkey_enc (line 237) | static void aes_setkey_enc(uint8_t *rk, const uint8_t *key)
  function aes_setkey_dec (line 242) | static void aes_setkey_dec(uint8_t *rk, const uint8_t *key)
  function encrypt_cbc (line 268) | static void encrypt_cbc( uint8_t* rk,
  function decrypt_cbc (line 291) | static void decrypt_cbc( uint8_t* rk,
  function aeshw_init (line 316) | static void aeshw_init(void)
  function AES_support_hwaccel (line 332) | int AES_support_hwaccel(void)
  function AES_CBC_encrypt_buffer (line 341) | void AES_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t le...
  function AES_CBC_decrypt_buffer (line 354) | void AES_CBC_decrypt_buffer(uint8_t* output, uint8_t* input, uint32_t le...
  function AES_ECB_encrypt_buffer (line 369) | void AES_ECB_encrypt_buffer(const uint8_t* input, const uint8_t* key, ui...
  function AES_ECB_decrypt_buffer (line 379) | void AES_ECB_decrypt_buffer(const uint8_t* input, const uint8_t* key, ui...
  function encrypt_cfb (line 389) | static void encrypt_cfb( uint8_t* rk,
  function decrypt_cfb (line 410) | static void decrypt_cfb( uint8_t* rk,
  function AES_CFB_encrypt_buffer (line 433) | void AES_CFB_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t le...
  function AES_CFB_decrypt_buffer (line 447) | void AES_CFB_decrypt_buffer(uint8_t* output, uint8_t* input, uint32_t le...

FILE: lib/aes_acc/aesarm.c
  function aesarm_supported (line 37) | int aesarm_supported( void )
  function aesarm_crypt_ecb (line 54) | void aesarm_crypt_ecb( int nr,

FILE: lib/aes_acc/aesni.c
  function aesni_supported (line 42) | int aesni_supported( void )
  function aesni_crypt_ecb (line 89) | void aesni_crypt_ecb( int nr,
  function aesni_inverse_key (line 132) | void aesni_inverse_key( unsigned char *invkey,
  function aesni_setkey_enc_128 (line 154) | void aesni_setkey_enc_128( unsigned char *rk,
  function aesni_setkey_enc_192 (line 204) | void aesni_setkey_enc_192( unsigned char *rk,
  function aesni_setkey_enc_256 (line 261) | void aesni_setkey_enc_256( unsigned char *rk,

FILE: lib/aes_faster_c/aes.cpp
  function polarssl_zeroize (line 61) | static void polarssl_zeroize( void *v, size_t n ) {
  function aes_gen_tables (line 392) | static void aes_gen_tables( void )
  function aes_init (line 470) | void aes_init( aes_context *ctx )
  function aes_free (line 475) | void aes_free( aes_context *ctx )
  function aes_setkey_enc (line 486) | int aes_setkey_enc( aes_context *ctx, const unsigned char *key,
  function aes_setkey_dec (line 598) | int aes_setkey_dec( aes_context *ctx, const unsigned char *key,
  function aes_crypt_ecb (line 711) | int aes_crypt_ecb( aes_context *ctx,
  function aes_crypt_cbc (line 824) | int aes_crypt_cbc( aes_context *ctx,
  function aes_crypt_cfb128 (line 890) | int aes_crypt_cfb128( aes_context *ctx,
  function aes_crypt_cfb8 (line 937) | int aes_crypt_cfb8( aes_context *ctx,
  function aes_crypt_ctr (line 971) | int aes_crypt_ctr( aes_context *ctx,
  function aes_self_test (line 1188) | int aes_self_test( int verbose )

FILE: lib/aes_faster_c/aes.h
  type UINT32 (line 51) | typedef UINT32 uint32_t;
  type aes_context (line 79) | typedef struct

FILE: lib/aes_faster_c/wrapper.cpp
  function AES_ECB_encrypt_buffer (line 15) | void AES_ECB_encrypt_buffer(const uint8_t* input, const uint8_t* key, ui...
  function AES_ECB_decrypt_buffer (line 27) | void AES_ECB_decrypt_buffer(const uint8_t* input, const uint8_t* key, ui...
  function AES_CBC_encrypt_buffer (line 40) | void AES_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t le...
  function AES_CBC_decrypt_buffer (line 55) | void AES_CBC_decrypt_buffer(uint8_t* output, uint8_t* input, uint32_t le...
  function AES_CFB_encrypt_buffer (line 70) | void AES_CFB_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t le...
  function AES_CFB_decrypt_buffer (line 86) | void AES_CFB_decrypt_buffer(uint8_t* output, uint8_t* input, uint32_t le...

FILE: lib/md5.cpp
  function polarssl_zeroize (line 48) | static void polarssl_zeroize( void *v, size_t n ) {
  function md5_init (line 75) | void md5_init( md5_context *ctx )
  function md5_free (line 80) | void md5_free( md5_context *ctx )
  function md5_starts (line 91) | void md5_starts( md5_context *ctx )
  function md5_process (line 102) | void md5_process( md5_context *ctx, const unsigned char data[64] )
  function md5_update (line 228) | void md5_update( md5_context *ctx, const unsigned char *input, size_t il...
  function md5_finish (line 278) | void md5_finish( md5_context *ctx, unsigned char output[16] )
  function md5 (line 306) | void md5( const unsigned char *input, size_t ilen, unsigned char output[...
  function md5_hmac_starts (line 327) | void md5_hmac_starts( md5_context *ctx, const unsigned char *key,
  function md5_hmac_update (line 358) | void md5_hmac_update( md5_context *ctx, const unsigned char *input,
  function md5_hmac_finish (line 367) | void md5_hmac_finish( md5_context *ctx, unsigned char output[16] )
  function md5_hmac_reset (line 383) | void md5_hmac_reset( md5_context *ctx )
  function md5_hmac (line 392) | void md5_hmac( const unsigned char *key, size_t keylen,

FILE: lib/pbkdf2-sha1.cpp
  function sha1_starts (line 85) | void sha1_starts(sha1_context * ctx)
  function sha1_process (line 97) | static void sha1_process(sha1_context * ctx, const unsigned char data[64])
  function sha1_update (line 256) | void sha1_update(sha1_context * ctx, const unsigned char *input, int ilen)
  function sha1_finish (line 302) | void sha1_finish(sha1_context * ctx, unsigned char output[20])
  function sha1 (line 331) | void sha1(const unsigned char *input, int ilen, unsigned char output[20])
  function sha1_hmac_starts (line 345) | void sha1_hmac_starts(sha1_context * ctx, const unsigned char *key, int ...
  function sha1_hmac_update (line 372) | void sha1_hmac_update(sha1_context * ctx, const unsigned char *input, in...
  function sha1_hmac_finish (line 380) | void sha1_hmac_finish(sha1_context * ctx, unsigned char output[20])
  function sha1_hmac_reset (line 395) | void sha1_hmac_reset(sha1_context * ctx)
  function sha1_hmac (line 404) | void sha1_hmac(const unsigned char *key, int keylen,
  function PKCS5_PBKDF2_HMAC_SHA1 (line 425) | void PKCS5_PBKDF2_HMAC_SHA1(const unsigned char *password, size_t plen,
  function do_test (line 573) | int do_test(testvector * tv)
  function print_hex (line 594) | static void print_hex(unsigned char *str, int len)
  function main (line 606) | int main(int argc,char * argv[])

FILE: lib/pbkdf2-sha256.cpp
  function sha2_starts (line 82) | void sha2_starts( sha2_context *ctx, int is224 )
  function sha2_process (line 115) | static void sha2_process( sha2_context *ctx, const unsigned char data[64] )
  function sha2_update (line 249) | void sha2_update( sha2_context *ctx, const unsigned char *input, size_t ...
  function sha2_finish (line 301) | void sha2_finish( sha2_context *ctx, unsigned char output[32] )
  function sha2 (line 335) | void sha2( const unsigned char *input, size_t ilen,
  function sha2_hmac_starts (line 350) | void sha2_hmac_starts( sha2_context *ctx, const unsigned char *key, size...
  function sha2_hmac_update (line 381) | void sha2_hmac_update( sha2_context *ctx, const unsigned char *input, si...
  function sha2_hmac_finish (line 389) | void sha2_hmac_finish( sha2_context *ctx, unsigned char output[32] )
  function sha2_hmac_reset (line 409) | void sha2_hmac_reset( sha2_context *ctx )
  function sha2_hmac (line 418) | void sha2_hmac( const unsigned char *key, size_t keylen,
  function PKCS5_PBKDF2_HMAC_SHA256 (line 439) | void PKCS5_PBKDF2_HMAC_SHA256(unsigned char *password, size_t plen,
  function do_test (line 670) | int do_test(testvector * tv)
  function main (line 694) | int main()
  function mbedtls_platform_zeroize (line 885) | void mbedtls_platform_zeroize( void *buf, size_t len )
  function hkdf_sha256_extract (line 890) | int hkdf_sha256_extract(
  function hkdf_sha256_expand (line 916) | int hkdf_sha256_expand( const unsigned char *prk,
  function hkdf_sha256 (line 1001) | int hkdf_sha256( const unsigned char *salt,
  function hex_to_number (line 1025) | int hex_to_number(char a)
  function base16_decode (line 1034) | int base16_decode(const char *a,unsigned char *buf)
  function main (line 1046) | int main()

FILE: libev/ev++.h
  function namespace (line 57) | namespace ev {
  function method_thunk (line 287) | void method_thunk (int revents, void *arg)
  function method_noargs_thunk (line 301) | void method_noargs_thunk (int revents, void *arg)
  function simpler_func_thunk (line 315) | void simpler_func_thunk (int revents, void *arg)
  function simplest_func_thunk (line 329) | void simplest_func_thunk (int revents, void *arg)
  function feed_fd_event (line 335) | void feed_fd_event (int fd, int revents) throw ()
  function feed_signal_event (line 340) | void feed_signal_event (int signum) throw ()
  type ev_loop (line 346) | struct ev_loop
  function loop_ref (line 352) | struct dynamic_loop : loop_ref
  type default_loop (line 377) | struct default_loop
  function loop_ref (line 399) | inline loop_ref get_default_loop () throw ()
  function set (line 428) | void set (EV_P) throw ()
  function set_ (line 442) | void set_ (const void *data, void (*cb)(EV_P_ ev_watcher *w, int revents...
  function function_thunk (line 456) | void function_thunk (EV_P_ ev_watcher *w, int revents)
  function method_thunk (line 477) | void method_thunk (EV_P_ ev_watcher *w, int revents)
  function method_noargs_thunk (line 491) | void method_noargs_thunk (EV_P_ ev_watcher *w, int revents)
  function is_active (line 504) | bool is_active () const throw ()
  function tstamp (line 520) | inline tstamp now (EV_P) throw ()
  function delay (line 525) | inline void delay (tstamp interval) throw ()
  function version_major (line 530) | inline int version_major () throw ()
  function version_minor (line 535) | inline int version_minor () throw ()
  function supported_backends (line 540) | inline unsigned int supported_backends () throw ()
  function recommended_backends (line 545) | inline unsigned int recommended_backends () throw ()
  function embeddable_backends (line 550) | inline unsigned int embeddable_backends () throw ()
  function set_allocator (line 555) | inline void set_allocator (void *(*cb)(void *ptr, long size) throw ()) t...
  function set_syserr_cb (line 560) | inline void set_syserr_cb (void (*cb)(const char *msg) throw ()) throw ()
  function set (line 615) | void set (int fd, int events) throw ()
  function set (line 623) | void set (int events) throw ()
  function start (line 631) | void start (int fd, int events) throw ()
  function again (line 653) | void again () throw ()
  function ev_tstamp (line 658) | ev_tstamp remaining ()
  function again (line 680) | void again () throw ()
  function set (line 689) | void set (int signum) throw ()
  function start (line 697) | void start (int signum) throw ()
  function update (line 740) | void update () throw ()
  function set (line 749) | void set () throw () { }
  function set (line 755) | void set () throw () { }
  function set (line 761) | void set () throw () { }
  function set_embed (line 767) | void set_embed (struct ev_loop *embedded_loop) throw ()
  function start (line 775) | void start (struct ev_loop *embedded_loop) throw ()
  function sweep (line 781) | void sweep ()
  function set (line 790) | void set () throw () { }
  function send (line 796) | void send () throw ()
  function async_pending (line 801) | bool async_pending () throw ()

FILE: libev/ev.c
  type signalfd_siginfo (line 463) | struct signalfd_siginfo
  type ecb_bool (line 813) | typedef int ecb_bool;
  type T (line 854) | typedef T type;
  function ecb_ctz32 (line 929) | int
  function ecb_ctz64 (line 960) | int
  function ecb_popcount32 (line 974) | int
  function ecb_ld32 (line 986) | int ecb_ld32 (uint32_t x)
  function ecb_ld64 (line 1006) | int ecb_ld64 (uint64_t x)
  function ecb_bool (line 1023) | ecb_bool ecb_is_pot32 (uint32_t x) { return !(x & (x - 1)); }
  function ecb_bool (line 1025) | ecb_bool ecb_is_pot64 (uint64_t x) { return !(x & (x - 1)); }
  function ecb_bitrev8 (line 1028) | uint8_t  ecb_bitrev8  (uint8_t  x)
  function ecb_bitrev16 (line 1035) | uint16_t ecb_bitrev16 (uint16_t x)
  function ecb_bitrev32 (line 1046) | uint32_t ecb_bitrev32 (uint32_t x)
  function ecb_popcount64 (line 1060) | int
  function ecb_rotl8 (line 1075) | uint8_t  ecb_rotl8  (uint8_t  x, unsigned int count) { return (x >> ( 8 ...
  function ecb_rotr8 (line 1076) | uint8_t  ecb_rotr8  (uint8_t  x, unsigned int count) { return (x << ( 8 ...
  function ecb_rotl16 (line 1077) | uint16_t ecb_rotl16 (uint16_t x, unsigned int count) { return (x >> (16 ...
  function ecb_rotr16 (line 1078) | uint16_t ecb_rotr16 (uint16_t x, unsigned int count) { return (x << (16 ...
  function ecb_rotl32 (line 1079) | uint32_t ecb_rotl32 (uint32_t x, unsigned int count) { return (x >> (32 ...
  function ecb_rotr32 (line 1080) | uint32_t ecb_rotr32 (uint32_t x, unsigned int count) { return (x << (32 ...
  function ecb_rotl64 (line 1081) | uint64_t ecb_rotl64 (uint64_t x, unsigned int count) { return (x >> (64 ...
  function ecb_rotr64 (line 1082) | uint64_t ecb_rotr64 (uint64_t x, unsigned int count) { return (x << (64 ...
  function ecb_bswap16 (line 1099) | uint16_t
  function ecb_bswap32 (line 1106) | uint32_t
  function ecb_bswap64 (line 1113) | uint64_t
  function ecb_unreachable (line 1125) | void ecb_unreachable (void) { }
  function ecb_byteorder_helper (line 1132) | uint32_t
  function ecb_bool (line 1160) | ecb_bool ecb_big_endian    (void) { return ecb_byteorder_helper () == 0x...
  function ecb_bool (line 1162) | ecb_bool ecb_little_endian (void) { return ecb_byteorder_helper () == 0x...
  function T (line 1172) | inline T ecb_div_rd (T val, T div)
  function T (line 1177) | inline T ecb_div_ru (T val, T div)
  function ecb_array_length (line 1189) | inline int ecb_array_length (const T (&arr)[N])
  function ecb_binary16_to_binary32 (line 1198) | uint32_t
  function ecb_binary32_to_binary16 (line 1230) | uint16_t
  function ecb_float_to_binary32 (line 1346) | uint32_t
  function ecb_binary32_to_float (line 1386) | float
  function ecb_double_to_binary64 (line 1416) | uint64_t
  function ecb_binary64_to_double (line 1456) | double
  function ecb_float_to_binary16 (line 1486) | uint16_t
  function ecb_binary16_to_float (line 1494) | float
  type ev_watcher (line 1546) | typedef ev_watcher *W;
  type ev_watcher_list (line 1547) | typedef ev_watcher_list *WL;
  type ev_watcher_time (line 1548) | typedef ev_watcher_time *WT;
  function noinline (line 1589) | noinline
  function ev_linux_version (line 1633) | static unsigned int
  function ev_printerr (line 1673) | static void
  function ecb_cold (line 1682) | ecb_cold
  function ev_syserr (line 1690) | static void
  function ecb_cold (line 1731) | ecb_cold
  function inline_speed (line 1738) | inline_speed void *
  type ANFD (line 1765) | typedef struct
  type ANPENDING (line 1784) | typedef struct
  type ANFS (line 1792) | typedef struct
  type ANHE (line 1801) | typedef struct {
  type WT (line 1811) | typedef WT ANHE;
  type ev_loop (line 1820) | struct ev_loop
  type ev_loop (line 1830) | struct ev_loop
  function ev_tstamp (line 1859) | ev_tstamp
  function inline_size (line 1877) | inline_size ev_tstamp
  function ev_tstamp (line 1893) | ev_tstamp
  function ev_sleep (line 1900) | void
  function inline_size (line 1930) | inline_size int
  function noinline (line 1987) | noinline
  function noinline (line 1993) | noinline
  function inline_speed (line 2013) | inline_speed void
  function inline_size (line 2020) | inline_size void
  function inline_speed (line 2028) | inline_speed void
  function inline_speed (line 2039) | inline_speed void
  function inline_speed (line 2056) | inline_speed void
  function ev_feed_fd_event (line 2065) | void
  function inline_size (line 2074) | inline_size void
  function inline_size (line 2134) | inline_size
  function fd_kill (line 2150) | void
  function fd_valid (line 2163) | int
  function fd_ebadf (line 2175) | static void
  function fd_enomem (line 2188) | static void
  function noinline (line 2202) | noinline
  function inline_speed (line 2219) | inline_speed void
  function inline_speed (line 2253) | inline_speed void
  function inline_speed (line 2303) | inline_speed void
  function inline_speed (line 2333) | inline_speed void
  function inline_size (line 2355) | inline_size void
  function inline_size (line 2365) | inline_size void
  type ANSIG (line 2379) | typedef struct
  function evpipe_init (line 2395) | static void
  function inline_speed (line 2440) | inline_speed void
  function pipecb (line 2491) | static void
  function ev_feed_signal (line 2558) | void
  function ev_sighandler (line 2574) | static void
  function noinline (line 2584) | noinline
  function sigfdcb (line 2611) | static void
  function inline_speed (line 2644) | inline_speed void
  function childcb (line 2668) | static void
  function ecb_cold (line 2712) | ecb_cold int
  function ecb_cold (line 2718) | ecb_cold int
  function enable_secure (line 2725) | int
  function ev_supported_backends (line 2736) | ecb_cold
  function ev_recommended_backends (line 2751) | ecb_cold
  function ev_embeddable_backends (line 2774) | ecb_cold
  function ev_backend (line 2787) | unsigned int
  function ev_iteration (line 2794) | unsigned int
  function ev_depth (line 2800) | unsigned int
  function ev_set_io_collect_interval (line 2806) | void
  function ev_set_timeout_collect_interval (line 2812) | void
  function ev_set_userdata (line 2818) | void
  function ev_set_invoke_pending_cb (line 2830) | void
  function ev_set_loop_release_cb (line 2836) | void
  function loop_init (line 2846) | static void
  function ecb_cold (line 2943) | ecb_cold
  function inline_size (line 3058) | inline_size void
  function ev_loop (line 3097) | ev_loop *
  function verify_watcher (line 3116) | static void
  function verify_heap (line 3126) | static void
  function array_verify (line 3142) | static void
  function ev_verify (line 3154) | void ecb_cold
  function ev_default_loop (line 3244) | int
  function ev_loop_fork (line 3274) | void
  function ev_invoke (line 3282) | void
  function ev_pending_count (line 3288) | unsigned int
  function noinline (line 3300) | noinline
  function inline_size (line 3324) | inline_size void
  function inline_size (line 3347) | inline_size void
  function noinline (line 3386) | noinline
  function inline_size (line 3412) | inline_size void
  function periodics_reschedule (line 3456) | static void
  function timers_reschedule (line 3480) | static void
  function inline_speed (line 3495) | inline_speed void
  function ev_run (line 3564) | int
  function ev_break (line 3736) | void
  function ev_ref (line 3742) | void
  function ev_unref (line 3748) | void
  function ev_now_update (line 3754) | void
  function ev_suspend (line 3760) | void
  function ev_resume (line 3766) | void
  function inline_size (line 3782) | inline_size void
  function inline_size (line 3789) | inline_size void
  function inline_speed (line 3805) | inline_speed void
  function ev_clear_pending (line 3815) | int
  function inline_size (line 3832) | inline_size void
  function inline_speed (line 3841) | inline_speed void
  function inline_size (line 3849) | inline_size void
  function noinline (line 3858) | noinline
  function noinline (line 3885) | noinline
  function noinline (line 3905) | noinline
  function noinline (line 3930) | noinline
  function noinline (line 3961) | noinline
  function ev_tstamp (line 3989) | ev_tstamp
  function noinline (line 3996) | noinline
  function noinline (line 4027) | noinline
  function noinline (line 4056) | noinline
  function noinline (line 4072) | noinline
  function noinline (line 4155) | noinline
  function ev_child_start (line 4197) | void
  function ev_child_stop (line 4214) | void
  function noinline (line 4249) | noinline
  function noinline (line 4324) | noinline
  function noinline (line 4342) | noinline
  function infy_cb (line 4374) | static void
  function ev_check_2625 (line 4390) | void
  function inline_size (line 4402) | inline_size int
  function inline_size (line 4413) | inline_size void
  function inline_size (line 4435) | inline_size void
  function ev_stat_stat (line 4489) | void
  function noinline (line 4498) | noinline
  function ev_stat_start (line 4539) | void
  function ev_stat_stop (line 4570) | void
  function ev_idle_start (line 4596) | void
  function ev_idle_stop (line 4619) | void
  function ev_prepare_start (line 4643) | void
  function ev_prepare_stop (line 4658) | void
  function ev_check_start (line 4681) | void
  function ev_check_stop (line 4696) | void
  function noinline (line 4719) | noinline
  function embed_io_cb (line 4726) | static void
  function embed_prepare_cb (line 4737) | static void
  function embed_fork_cb (line 4753) | static void
  function embed_idle_cb (line 4771) | static void
  function ev_embed_start (line 4778) | void
  function ev_embed_stop (line 4809) | void
  function ev_fork_start (line 4829) | void
  function ev_fork_stop (line 4844) | void
  function ev_cleanup_start (line 4867) | void
  function ev_cleanup_stop (line 4884) | void
  function ev_async_start (line 4908) | void
  function ev_async_stop (line 4927) | void
  function ev_async_send (line 4948) | void
  type ev_once (line 4958) | struct ev_once
  function once_cb (line 4966) | static void
  function once_cb_io (line 4979) | static void
  function once_cb_to (line 4987) | static void
  function ev_once (line 4995) | void
  type ev_embed (line 5044) | struct ev_embed
  type ev_stat (line 5067) | struct ev_stat

FILE: libev/ev.h
  type ev_tstamp (line 153) | typedef double ev_tstamp;
  type ev_loop (line 172) | struct ev_loop
  type ev_watcher (line 298) | typedef struct ev_watcher
  type ev_watcher_list (line 304) | typedef struct ev_watcher_list
  type ev_watcher_time (line 310) | typedef struct ev_watcher_time
  type ev_io (line 317) | typedef struct ev_io
  type ev_timer (line 327) | typedef struct ev_timer
  type ev_periodic (line 336) | typedef struct ev_periodic
  type ev_signal (line 347) | typedef struct ev_signal
  type ev_child (line 357) | typedef struct ev_child
  type ev_statdata (line 370) | typedef struct _stati64 ev_statdata;
  type ev_statdata (line 372) | typedef struct stat ev_statdata;
  type ev_stat (line 377) | typedef struct ev_stat
  type ev_idle (line 394) | typedef struct ev_idle
  type ev_prepare (line 403) | typedef struct ev_prepare
  type ev_check (line 410) | typedef struct ev_check
  type ev_fork (line 418) | typedef struct ev_fork
  type ev_cleanup (line 427) | typedef struct ev_cleanup
  type ev_embed (line 436) | typedef struct ev_embed
  type ev_async (line 457) | typedef struct ev_async
  type ev_watcher (line 470) | struct ev_watcher
  type ev_watcher_list (line 471) | struct ev_watcher_list
  type ev_io (line 473) | struct ev_io
  type ev_timer (line 474) | struct ev_timer
  type ev_periodic (line 475) | struct ev_periodic
  type ev_signal (line 476) | struct ev_signal
  type ev_child (line 477) | struct ev_child
  type ev_stat (line 479) | struct ev_stat
  type ev_idle (line 482) | struct ev_idle
  type ev_prepare (line 484) | struct ev_prepare
  type ev_check (line 485) | struct ev_check
  type ev_fork (line 487) | struct ev_fork
  type ev_cleanup (line 490) | struct ev_cleanup
  type ev_embed (line 493) | struct ev_embed
  type ev_async (line 496) | struct ev_async
  function ev_loop (line 563) | ev_loop *
  function EV_INLINE (line 571) | EV_INLINE int
  function EV_INLINE (line 588) | EV_INLINE ev_tstamp
  function EV_INLINE (line 595) | EV_INLINE int
  function EV_INLINE (line 835) | EV_INLINE void ev_loop   (EV_P_ int flags) { ev_run   (EV_A_ flags); }
  function EV_INLINE (line 836) | EV_INLINE void ev_unloop (EV_P_ int how  ) { ev_break (EV_A_ how  ); }
  function EV_INLINE (line 837) | EV_INLINE void ev_default_destroy (void) { ev_loop_destroy (EV_DEFAULT); }
  function EV_INLINE (line 838) | EV_INLINE void ev_default_fork    (void) { ev_loop_fork    (EV_DEFAULT); }
  function ev_loop_count (line 840) | EV_INLINE unsigned int ev_loop_count  (EV_P) { return ev_iteration  (EV_...
  function ev_loop_depth (line 841) | EV_INLINE unsigned int ev_loop_depth  (EV_P) { return ev_depth      (EV_...
  function EV_INLINE (line 842) | EV_INLINE void         ev_loop_verify (EV_P) {        ev_verify     (EV_...
  type ev_loop (line 846) | typedef struct ev_loop ev_loop;

FILE: libev/ev_epoll.c
  function epoll_modify (line 70) | static void
  function epoll_poll (line 141) | static void
  function inline_size (line 238) | inline_size
  function inline_size (line 264) | inline_size
  function inline_size (line 272) | inline_size

FILE: libev/ev_kqueue.c
  function inline_speed (line 46) | inline_speed
  function kqueue_modify (line 64) | static void
  function kqueue_poll (line 86) | static void
  function inline_size (line 156) | inline_size
  function inline_size (line 181) | inline_size
  function inline_size (line 189) | inline_size

FILE: libev/ev_poll.c
  function inline_size (line 42) | inline_size
  function poll_modify (line 52) | static void
  function poll_poll (line 89) | static void
  function inline_size (line 130) | inline_size
  function inline_size (line 144) | inline_size

FILE: libev/ev_port.c
  function inline_speed (line 58) | inline_speed
  function port_modify (line 78) | static void
  function port_poll (line 93) | static void
  function inline_size (line 140) | inline_size
  function inline_size (line 168) | inline_size
  function inline_size (line 175) | inline_size

FILE: libev/ev_select.c
  function select_poll (line 139) | static void
  function inline_size (line 274) | inline_size
  function inline_size (line 304) | inline_size

FILE: libev/ev_vars.h
  type ev_prepare (line 149) | struct ev_prepare

FILE: libev/ev_win32.c
  function SOCKET (line 48) | static SOCKET
  function ev_pipe (line 59) | static int
  function ev_tstamp (line 147) | ev_tstamp

FILE: libev/event.c
  type event_base (line 59) | struct event_base
  type event_base (line 64) | struct event_base
  function ev_tstamp (line 66) | static ev_tstamp
  type event_base (line 98) | struct event_base
  type event_base (line 100) | struct event_base
  type event_base (line 104) | struct event_base
  type event_base (line 111) | struct event_base
  type event_base (line 116) | struct event_base
  type event_base (line 120) | struct event_base
  function event_base_free (line 127) | void event_base_free (struct event_base *base)
  function event_dispatch (line 137) | int event_dispatch (void)
  function event_set_log_callback (line 143) | void event_set_log_callback (event_log_cb cb)
  function event_loop (line 149) | int event_loop (int flags)
  function event_loopexit (line 154) | int event_loopexit (struct timeval *tv)
  function event_callback_fn (line 159) | event_callback_fn event_get_callback
  function ev_x_cb (line 165) | static void
  function ev_x_cb_sig (line 174) | static void
  function ev_x_cb_io (line 185) | static void
  function ev_x_cb_to (line 196) | static void
  function event_set (line 206) | void event_set (struct event *ev, int fd, short events, void (*cb)(int, ...
  function event_once (line 225) | int event_once (int fd, short events, void (*cb)(int, short, void *), vo...
  function event_add (line 230) | int event_add (struct event *ev, struct timeval *tv)
  function event_del (line 272) | int event_del (struct event *ev)
  function event_active (line 289) | void event_active (struct event *ev, int res, short ncalls)
  function event_pending (line 303) | int event_pending (struct event *ev, short events, struct timeval *tv)
  function event_priority_init (line 337) | int event_priority_init (int npri)
  function event_priority_set (line 342) | int event_priority_set (struct event *ev, int pri)
  function event_base_set (line 349) | int event_base_set (struct event_base *base, struct event *ev)
  function event_base_loop (line 356) | int event_base_loop (struct event_base *base, int flags)
  function event_base_dispatch (line 363) | int event_base_dispatch (struct event_base *base)
  function ev_x_loopexit_cb (line 368) | static void
  function event_base_loopexit (line 376) | int event_base_loopexit (struct event_base *base, struct timeval *tv)
  type ev_x_once (line 386) | struct ev_x_once
  function ev_x_once_cb (line 393) | static void
  function event_base_once (line 402) | int event_base_once (struct event_base *base, int fd, short events, void...
  function event_base_priority_init (line 419) | int event_base_priority_init (struct event_base *base, int npri)

FILE: libev/event.h
  type event_base (line 69) | struct event_base
  type event (line 80) | struct event
  type event (line 100) | struct event
  type event_base (line 134) | struct event_base
  type timeval (line 138) | struct timeval
  type event (line 148) | struct event
  type timeval (line 149) | struct timeval
  type event (line 151) | struct event
  type timeval (line 151) | struct timeval
  type event (line 152) | struct event
  type event (line 153) | struct event
  type event (line 155) | struct event
  type timeval (line 155) | struct timeval
  type event (line 158) | struct event
  type event_base (line 160) | struct event_base
  type event_base (line 161) | struct event_base
  type event_base (line 162) | struct event_base
  type event (line 162) | struct event
  type event_base (line 163) | struct event_base
  type event_base (line 164) | struct event_base
  type timeval (line 164) | struct timeval
  type event_base (line 165) | struct event_base
  type event_base (line 166) | struct event_base
  type timeval (line 166) | struct timeval
  type event_base (line 167) | struct event_base

FILE: libev/event_compat.h
  type u_char (line 36) | typedef unsigned char u_char;
  type u_short (line 37) | typedef unsigned short u_short;
  type type (line 52) | struct type
  type type (line 60) | struct type
  type type (line 61) | struct type
  type evkeyval (line 70) | struct evkeyval {
  type event_list (line 79) | struct event_list
  type evkeyvalq (line 80) | struct evkeyvalq
  type eventop (line 91) | struct eventop {
  type evbuffer (line 103) | struct evbuffer {
  type bufferevent (line 122) | struct bufferevent
  type bufferevent (line 123) | struct bufferevent
  type bufferevent (line 124) | struct bufferevent
  type event_watermark (line 126) | struct event_watermark {
  type bufferevent (line 131) | struct bufferevent {
  type bufferevent (line 152) | struct bufferevent
  type event_base (line 154) | struct event_base
  type bufferevent (line 154) | struct bufferevent
  type bufferevent (line 155) | struct bufferevent
  type bufferevent (line 156) | struct bufferevent
  type bufferevent (line 157) | struct bufferevent
  type bufferevent (line 158) | struct bufferevent
  type evbuffer (line 158) | struct evbuffer
  type bufferevent (line 159) | struct bufferevent
  type bufferevent (line 160) | struct bufferevent
  type bufferevent (line 161) | struct bufferevent
  type bufferevent (line 162) | struct bufferevent
  type evbuffer (line 170) | struct evbuffer
  type evbuffer (line 171) | struct evbuffer
  type evbuffer (line 172) | struct evbuffer
  type evbuffer (line 173) | struct evbuffer
  type evbuffer (line 174) | struct evbuffer
  type evbuffer (line 175) | struct evbuffer
  type evbuffer (line 176) | struct evbuffer
  type evbuffer (line 176) | struct evbuffer
  type evbuffer (line 177) | struct evbuffer
  type evbuffer (line 178) | struct evbuffer
  type evbuffer (line 179) | struct evbuffer
  type evbuffer (line 180) | struct evbuffer
  type evbuffer (line 181) | struct evbuffer
  type evbuffer (line 182) | struct evbuffer
  type evbuffer (line 183) | struct evbuffer
  type evbuffer (line 183) | struct evbuffer
  type evbuffer (line 193) | struct evbuffer
  type evbuffer (line 196) | struct evbuffer
  type evbuffer (line 198) | struct evbuffer
  type evbuffer (line 200) | struct evbuffer
  type evbuffer (line 203) | struct evbuffer
  type timeval (line 204) | struct timeval
  type evbuffer (line 206) | struct evbuffer
  type evbuffer (line 206) | struct evbuffer
  type evbuffer (line 207) | struct evbuffer
  type evbuffer (line 208) | struct evbuffer
  type evbuffer (line 209) | struct evbuffer
  type evbuffer (line 210) | struct evbuffer
  type evbuffer (line 212) | struct evbuffer
  type evbuffer (line 215) | struct evbuffer
  type evbuffer (line 218) | struct evbuffer
  type evbuffer (line 221) | struct evbuffer
  type timeval (line 222) | struct timeval

FILE: log.cpp
  function log0 (line 9) | void log0(const char* file, const char* function, int line, int level, c...
  function log_bare (line 45) | void log_bare(int level, const char* str, ...) {

FILE: main.cpp
  function sigpipe_cb (line 10) | void sigpipe_cb(struct ev_loop *l, ev_signal *w, int revents) {
  function sigterm_cb (line 14) | void sigterm_cb(struct ev_loop *l, ev_signal *w, int revents) {
  function sigint_cb (line 19) | void sigint_cb(struct ev_loop *l, ev_signal *w, int revents) {
  function main (line 27) | int main(int argc, char *argv[]) {

FILE: misc.cpp
  function process_lower_level_arg (line 94) | int process_lower_level_arg()  // handle --lower-level option
  function print_help (line 122) | void print_help() {
  function load_config (line 198) | int load_config(char *file_name, int &argc, vector<string> &argv)  // lo...
  function process_log_level (line 221) | int process_log_level(int argc, char *argv[])  // process  --log-level a...
  function process_arg (line 247) | void process_arg(int argc, char *argv[])  // process all options
  function pre_process_arg (line 737) | void pre_process_arg(int argc, char *argv[])  // mainly for load conf file
  function iptables_rule (line 821) | void iptables_rule()  // handles -a -g --gen-add  --keep-rule --clear --...
  function unit_test (line 965) | int unit_test() {
  function set_timer (line 1017) | int set_timer(int epollfd, int &timer_fd)  // put a timer_fd into epoll,...
  function set_timer_server (line 1045) | int set_timer_server(int epollfd, int &timer_fd, fd64_t &fd64)  // only ...
  function handle_lower_level (line 1075) | int handle_lower_level(raw_info_t &raw_info)  // fill lower_level info,w...
  function iptables_gen_add (line 1110) | int iptables_gen_add(const char *s, u32_t const_id) {
  function iptables_rule_init (line 1133) | int iptables_rule_init(const char *s, u32_t const_id, int keep) {
  function keep_iptables_rule (line 1172) | int keep_iptables_rule()  // magic to work on a machine without grep/ipt...
  function clear_iptables_rule (line 1217) | int clear_iptables_rule() {
  function iptables_rule (line 1232) | void iptables_rule()  // handles -a -g --gen-add  --keep-rule --clear --...
  function signal_handler (line 1320) | void signal_handler(int sig) {

FILE: misc.h
  type server_current_state_t (line 63) | enum server_current_state_t { server_idle = 0,
  type client_current_state_t (line 66) | enum client_current_state_t { client_idle = 0,
  type raw_mode_t (line 73) | enum raw_mode_t { mode_faketcp = 0,
  type program_mode_t (line 77) | enum program_mode_t { unset_mode = 0,

FILE: network.cpp
  type ev_loop (line 86) | struct ev_loop
  type bpf_program (line 90) | struct bpf_program
  type sock_filter (line 97) | struct sock_filter
  type sock_filter (line 112) | struct sock_filter
  type sock_filter (line 142) | struct sock_filter
  type sock_filter (line 163) | struct sock_filter
  type sock_filter (line 178) | struct sock_filter
  type sock_filter (line 191) | struct sock_filter
  type sock_filter (line 200) | struct sock_filter
  function my_packet_handler (line 289) | void my_packet_handler(
  type pcap_pkthdr (line 321) | struct pcap_pkthdr
  type ev_loop (line 367) | struct ev_loop
  type ev_async (line 367) | struct ev_async
  function init_raw_socket (line 371) | int init_raw_socket() {
  function init_raw_socket (line 475) | int init_raw_socket() {
  function init_filter (line 666) | void init_filter(int port) {
  function init_filter (line 723) | void init_filter(int port) {
  function remove_filter (line 841) | void remove_filter() {
  function init_ifindex (line 854) | int init_ifindex(const char *if_name, int fd, int &index) {
  function interface_has_arp (line 876) | bool interface_has_arp(const char *interface) {
  type route_info_t (line 890) | struct route_info_t {
  function find_route_entry (line 902) | vector<int> find_route_entry(const vector<route_info_t> &route_info_vec,...
  function find_direct_dest (line 928) | int find_direct_dest(const vector<route_info_t> &route_info_vec, u32_t i...
  type arp_info_t (line 952) | struct arp_info_t {
  function find_arp (line 961) | int find_arp(const vector<arp_info_t> &arp_info_vec, u32_t ip, string if...
  function find_lower_level_info (line 985) | int find_lower_level_info(u32_t ip, u32_t &dest_ip, string &if_name, str...
  function send_raw_packet (line 1064) | int send_raw_packet(raw_info_t &raw_info, const char *packet, int len) {
  function send_raw_packet (line 1105) | int send_raw_packet(raw_info_t &raw_info, const char *packet, int len) {
  function send_raw_ip (line 1162) | int send_raw_ip(raw_info_t &raw_info, const char *payload, int payloadle...
  function pre_recv_raw_packet (line 1244) | int pre_recv_raw_packet() {
  function discard_raw_packet (line 1284) | int discard_raw_packet() {
  function recv_raw_packet (line 1290) | int recv_raw_packet(char *&packet, int &len, int peek) {
  function recv_raw_packet (line 1315) | int recv_raw_packet(char *&packet, int &len, int peek) {
  function recv_raw_ip (line 1325) | int recv_raw_ip(raw_info_t &raw_info, char *&payload, int &payloadlen) {
  function peek_raw (line 1434) | int peek_raw(raw_info_t &raw_info) {
  function send_raw_icmp (line 1505) | int send_raw_icmp(raw_info_t &raw_info, const char *payload, int payload...
  function send_raw_udp (line 1562) | int send_raw_udp(raw_info_t &raw_info, const char *payload, int payloadl...
  function send_raw_tcp (line 1619) | int send_raw_tcp(raw_info_t &raw_info, const char *payload, int payloadl...
  function recv_raw_icmp (line 1924) | int recv_raw_icmp(raw_info_t &raw_info, char *&payload, int &payloadlen) {
  function recv_raw_udp (line 2020) | int recv_raw_udp(raw_info_t &raw_info, char *&payload, int &payloadlen) {
  function parse_tcp_option (line 2112) | int parse_tcp_option(char *option_begin, char *option_end, packet_info_t...
  function recv_raw_tcp (line 2166) | int recv_raw_tcp(raw_info_t &raw_info, char *&payload, int &payloadlen) {
  function send_raw0 (line 2522) | int send_raw0(raw_info_t &raw_info, const char *payload, int payloadlen) {
  function recv_raw0 (line 2543) | int recv_raw0(raw_info_t &raw_info, char *&payload, int &payloadlen) {
  function after_send_raw0 (line 2558) | int after_send_raw0(raw_info_t &raw_info) {
  function after_recv_raw0 (line 2605) | int after_recv_raw0(raw_info_t &raw_info) {
  function get_src_adress2 (line 2702) | int get_src_adress2(address_t &output_addr, address_t remote_addr) {
  function try_to_list_and_bind2 (line 2762) | int try_to_list_and_bind2(int &fd, address_t address)  // try to bind to...
  function client_bind_to_a_new_port2 (line 2812) | int client_bind_to_a_new_port2(int &fd, const address_t &address)  // fi...

FILE: network.h
  type ev_loop (line 37) | struct ev_loop
  type icmphdr (line 50) | struct icmphdr {
  type my_iphdr (line 59) | struct my_iphdr {
  type my_udphdr (line 79) | struct my_udphdr {
  type my_tcphdr (line 98) | struct my_tcphdr {
  type my_ip6hdr (line 158) | struct my_ip6hdr {
  type my_icmphdr (line 179) | struct my_icmphdr {
  type pseudo_header (line 187) | struct pseudo_header {
  type pseudo_header6 (line 195) | struct pseudo_header6 {
  type packet_info_t (line 204) | struct packet_info_t  // todo change this to union
  type raw_info_t (line 238) | struct raw_info_t {

FILE: pcap_wrapper.cpp
  type bpf_program (line 18) | struct bpf_program
  type bpf_program (line 23) | struct bpf_program
  type bpf_program (line 25) | struct bpf_program
  type init_pcap_t (line 35) | struct init_pcap_t {
    method init_pcap_t (line 36) | init_pcap_t() {
  function init_npcap_dll_path (line 42) | static void init_npcap_dll_path() {
  function init_pcap (line 65) | int init_pcap() {

FILE: pcap_wrapper.h
  type bpf_program (line 10) | struct bpf_program {
  type pcap_t (line 14) | struct pcap_t {
  type bpf_u_int32 (line 18) | typedef unsigned int bpf_u_int32;
  type my_timeval (line 20) | typedef struct my_timeval {
  type pcap_pkthdr (line 25) | struct pcap_pkthdr {
  type pcap_direction_t (line 31) | typedef enum {
  type pcap_addr (line 37) | struct pcap_addr {
  type pcap_if (line 45) | struct pcap_if {
  type pcap_if_t (line 53) | typedef struct pcap_if pcap_if_t;
  type pcap_addr_t (line 54) | typedef struct pcap_addr pcap_addr_t;
  type u_char (line 56) | typedef unsigned char u_char;
  type pcap_pkthdr (line 75) | struct pcap_pkthdr
  type bpf_program (line 92) | struct bpf_program
  type bpf_program (line 97) | struct bpf_program
  type bpf_program (line 99) | struct bpf_program
  function pcap_set_immediate_mode (line 109) | inline int pcap_set_immediate_mode(pcap_t *, int) {

FILE: server.cpp
  function server_on_timer_multi (line 19) | int server_on_timer_multi(conn_info_t &conn_info)  // for server. called...
  function server_on_raw_recv_ready (line 70) | int server_on_raw_recv_ready(conn_info_t &conn_info, char *ip_port, char...
  function server_on_raw_recv_pre_ready (line 196) | int server_on_raw_recv_pre_ready(conn_info_t &conn_info, char *ip_port, ...
  function server_on_raw_recv_handshake1 (line 313) | int server_on_raw_recv_handshake1(conn_info_t &conn_info, char *ip_port,...
  function server_on_recv_safer_multi (line 377) | int server_on_recv_safer_multi(conn_info_t &conn_info, char type, char *...
  function server_on_raw_recv_multi (line 380) | int server_on_raw_recv_multi()  // called when server received an raw pa...
  function server_on_udp_recv (line 563) | int server_on_udp_recv(conn_info_t &conn_info, fd64_t fd64) {
  function server_event_loop (line 609) | int server_event_loop() {
Condensed preview — 99 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,650K chars).
[
  {
    "path": ".clang-format",
    "chars": 71,
    "preview": "SortIncludes: false\nBasedOnStyle: Google\nColumnLimit: 0\nIndentWidth: 4\n"
  },
  {
    "path": ".gitattributes",
    "chars": 36,
    "preview": "lib/aes_acc/asm/* linguist-vendored\n"
  },
  {
    "path": "CMakeLists.txt",
    "chars": 992,
    "preview": "#note: experimental\n#      currently only used for generating `compile_commands.json` for clangd.\n#      to build this p"
  },
  {
    "path": "ISSUE_TEMPLATE.md",
    "chars": 14,
    "preview": "English Only.\n"
  },
  {
    "path": "LICENSE.md",
    "chars": 1088,
    "preview": "MIT License\n\nCopyright (c) 2017 Yu Wang (wangyucn at gmail.com)\n\nPermission is hereby granted, free of charge, to any pe"
  },
  {
    "path": "README.md",
    "chars": 13589,
    "preview": "# Udp2raw-tunnel\n\n\nA Tunnel which turns UDP Traffic into Encrypted FakeTCP/UDP/ICMP Traffic by using Raw Socket, helps y"
  },
  {
    "path": "client.cpp",
    "chars": 34785,
    "preview": "#include \"common.h\"\n#include \"network.h\"\n#include \"connection.h\"\n#include \"misc.h\"\n#include \"log.h\"\n#include \"lib/md5.h\""
  },
  {
    "path": "common.cpp",
    "chars": 30195,
    "preview": "/*\n * comm.cpp\n *\n *  Created on: Jul 29, 2017\n *      Author: wangyu\n */\n\n#include \"common.h\"\n#include \"log.h\"\n#include"
  },
  {
    "path": "common.h",
    "chars": 12419,
    "preview": "/*\n * common.h\n *\n *  Created on: Jul 29, 2017\n *      Author: wangyu\n */\n\n#ifndef UDP2RAW_COMMON_H_\n#define UDP2RAW_COM"
  },
  {
    "path": "connection.cpp",
    "chars": 21628,
    "preview": "/*\n * connection.cpp\n *\n *  Created on: Sep 23, 2017\n *      Author: root\n */\n\n#include \"connection.h\"\n#include \"encrypt"
  },
  {
    "path": "connection.h",
    "chars": 10321,
    "preview": "/*\n * connection.h\n *\n *  Created on: Sep 23, 2017\n *      Author: root\n */\n\n#ifndef CONNECTION_H_\n#define CONNECTION_H_"
  },
  {
    "path": "doc/README.zh-cn.md",
    "chars": 11483,
    "preview": "# Udp2raw-tunnel \r\n![image2](/images/image0.PNG)\r\nudp2raw tunnel,通过raw socket给UDP包加上TCP或ICMP header,进而绕过UDP屏蔽或QoS,或在UDP不"
  },
  {
    "path": "doc/android_guide.md",
    "chars": 918,
    "preview": "# How to run udp2raw on a rooted android device(arm cpu)\n\nThere is currently no GUI for udp2raw on android.Make sure you"
  },
  {
    "path": "doc/build_guide.md",
    "chars": 2852,
    "preview": "# udp2raw build guide\n\nthe guide on how to build udp2raw\n\n## Build udp2raw for a specific platform\n\n### linux platform w"
  },
  {
    "path": "doc/build_guide.zh-cn.md",
    "chars": 1759,
    "preview": "# udp2raw编译方法\n本文演示怎么把udp2raw编译到自己所需的平台。\n\n## 可以本地编译的linux平台\n比如电脑、树莓派\n\n##### 首先安装git\ndebian/ubuntun执行:\n```\nsudo apt-get in"
  },
  {
    "path": "doc/finalspeed_step_by_step/11",
    "chars": 3,
    "preview": "11\n"
  },
  {
    "path": "doc/finalspeed_step_by_step.md",
    "chars": 1983,
    "preview": "# udp2raw+finalspeed 加速tcp流量 Step by Step 教程\n![image](finalspeed_step_by_step/Capture0.PNG)\n\n##### 背景\n国内有些ISP会对UDP做QOS或屏"
  },
  {
    "path": "doc/kcptun_step_by_step.md",
    "chars": 1482,
    "preview": "# udp2raw+kcptun 加速tcp流量 Step by Step 教程\n![image](kcptun_step_by_step/Capture00.PNG)\n\n本教程会一步一步演示用udp2raw+kcptun加速SSH流量的过"
  },
  {
    "path": "doc/openvpn_guide.md",
    "chars": 2244,
    "preview": "# udp2raw+openvpn config guide\n![image_vpn](/images/openvpn.PNG)\n\n![image4](/images/image4.PNG)\n\n# udp2raw command\n#### "
  },
  {
    "path": "encrypt.cpp",
    "chars": 19006,
    "preview": "#include \"lib/aes-common.h\"\n#include \"lib/md5.h\"\n#include \"lib/pbkdf2-sha1.h\"\n#include \"lib/pbkdf2-sha256.h\"\n#include <s"
  },
  {
    "path": "encrypt.h",
    "chars": 1539,
    "preview": "#ifndef UDP2RAW_ENCRYPTION_H_\n#define UDP2RAW_ENCRYPTION_H_\n\n//#include \"aes.h\"\n//#include \"md5.h\"\n#include \"common.h\"\n\n"
  },
  {
    "path": "example.conf",
    "chars": 370,
    "preview": "# Basically this file is the equivalent to splitting the command line options into multiple lines\n# Each line should con"
  },
  {
    "path": "fd_manager.cpp",
    "chars": 1280,
    "preview": "/*\n * fd_manager.cpp\n *\n *  Created on: Sep 25, 2017\n *      Author: root\n */\n\n#include \"fd_manager.h\"\nint fd_manager_t:"
  },
  {
    "path": "fd_manager.h",
    "chars": 1009,
    "preview": "/*\n * fd_manager.h\n *\n *  Created on: Sep 25, 2017\n *      Author: root\n */\n\n#ifndef FD_MANAGER_H_\n#define FD_MANAGER_H_"
  },
  {
    "path": "images/speedtest/111",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": "images/wiki/111",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": "lib/aes-common.h",
    "chars": 759,
    "preview": "/*\n *  this file comes from https://github.com/kokke/tiny-AES128-C\n */\n\n#pragma once\n\n#include <stdint.h>\n\n\nvoid AES_ECB"
  },
  {
    "path": "lib/aes_acc/aesacc.c",
    "chars": 11923,
    "preview": "/*\n * This file is adapted from PolarSSL 1.3.19 (GPL)\n */\n\n#include \"aesni.h\"\n#include \"aesarm.h\"\n#include <stdint.h>\n#i"
  },
  {
    "path": "lib/aes_acc/aesarm.c",
    "chars": 3528,
    "preview": "/*\n * This file is adapted from https://github.com/CriticalBlue/mbedtls\n */\n\n/*\n *  ARMv8-A Cryptography Extension AES s"
  },
  {
    "path": "lib/aes_acc/aesarm.h",
    "chars": 2189,
    "preview": "/*\n * This file is adapted from https://github.com/CriticalBlue/mbedtls\n */\n\n/**\n * \\file aes_armv8a_ce.h\n *\n * \\brief A"
  },
  {
    "path": "lib/aes_acc/aesarm_table.h",
    "chars": 6854,
    "preview": "/*\n * This file is adapted from PolarSSL 1.3.19 (GPL)\n */\n\n/*\n * Forward S-box\n */\nstatic const unsigned char FSb[256] ="
  },
  {
    "path": "lib/aes_acc/aesni.c",
    "chars": 12624,
    "preview": "/*\n * This file is adapted from PolarSSL 1.3.19 (GPL)\n */\n\n/*\n *  AES-NI support functions\n *\n *  Copyright (C) 2006-201"
  },
  {
    "path": "lib/aes_acc/aesni.h",
    "chars": 3334,
    "preview": "/*\n * This file is adapted from PolarSSL 1.3.19 (GPL)\n */\n\n/**\n * \\file aesni.h\n *\n * \\brief AES-NI for hardware AES acc"
  },
  {
    "path": "lib/aes_acc/asm/arm.S",
    "chars": 30214,
    "preview": "@ Copyright 2007-2016 The OpenSSL Project Authors. All Rights Reserved.\n@\n@ Licensed under the OpenSSL license (the \"Lic"
  },
  {
    "path": "lib/aes_acc/asm/arm64.S",
    "chars": 41608,
    "preview": ".text\n\n.type\t_vpaes_consts,%object\n.align\t7\t// totally strategic alignment\n_vpaes_consts:\n.Lk_mc_forward:\t//\tmc_forward\n"
  },
  {
    "path": "lib/aes_acc/asm/arm_arch.h",
    "chars": 2588,
    "preview": "/*\n * Copyright 2011-2016 The OpenSSL Project Authors. All Rights Reserved.\n *\n * Licensed under the OpenSSL license (th"
  },
  {
    "path": "lib/aes_acc/asm/mips.S",
    "chars": 39422,
    "preview": ".text\n#ifdef OPENSSL_FIPSCANISTER\n# include <openssl/fipssyms.h>\n#endif\n\n#if defined(__mips_smartmips) && !defined(_MIPS"
  },
  {
    "path": "lib/aes_acc/asm/mips_be.S",
    "chars": 39419,
    "preview": ".text\n#ifdef OPENSSL_FIPSCANISTER\n# include <openssl/fipssyms.h>\n#endif\n\n#if defined(__mips_smartmips) && !defined(_MIPS"
  },
  {
    "path": "lib/aes_acc/asm/x64.S",
    "chars": 13671,
    "preview": ".text\t\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n.type\t_vpaes_encrypt_core,@function\n.align\t16\n_vpaes_encrypt_core:\n\tmovq\t%rdx,%r9\n\tmovq\t$16,%r11\n"
  },
  {
    "path": "lib/aes_acc/asm/x86.S",
    "chars": 68220,
    "preview": ".file\t\"aes-586.s\"\n.text\n.type\t_x86_AES_encrypt_compact,@function\n.align\t16\n_x86_AES_encrypt_compact:\n\tmovl\t%edi,20(%esp)"
  },
  {
    "path": "lib/aes_faster_c/aes.cpp",
    "chars": 47658,
    "preview": "/*\n *  FIPS-197 compliant AES implementation\n *\n *  Copyright (C) 2006-2014, Brainspark B.V.\n *\n *  This file is part of"
  },
  {
    "path": "lib/aes_faster_c/aes.h",
    "chars": 8253,
    "preview": "/**\n * \\file aes.h\n *\n * \\brief AES block cipher\n *\n *  Copyright (C) 2006-2014, Brainspark B.V.\n *\n *  This file is par"
  },
  {
    "path": "lib/aes_faster_c/wrapper.cpp",
    "chars": 2656,
    "preview": "#include \"aes.h\"\n#include <stdio.h>\n#include <stdlib.h>\n#include <assert.h>\n\n#if defined(AES256) && (AES256 == 1)\n#defin"
  },
  {
    "path": "lib/md5.cpp",
    "chars": 10867,
    "preview": "/*\n * This file is adapted from PolarSSL 1.3.19 (GPL)\n */\n\n/*\n *  RFC 1321 compliant MD5 implementation\n *\n *  Copyright"
  },
  {
    "path": "lib/md5.h",
    "chars": 170,
    "preview": "#ifndef UDP2RAW_MD5_H_\n#define UDP2RAW_MD5_H_\n#include <stdint.h>\n#include <stddef.h>\n\nvoid md5(const uint8_t *initial_m"
  },
  {
    "path": "lib/pbkdf2-sha1.cpp",
    "chars": 20832,
    "preview": "/*\n   this file is from https://github.com/kholia/PKCS5_PBKDF2\n\n*\n *  FIPS-180-1 compliant SHA-1 implementation\n *\n *  C"
  },
  {
    "path": "lib/pbkdf2-sha1.h",
    "chars": 486,
    "preview": "#pragma once\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\nvoid sha1(const unsigned char *input, int ilen"
  },
  {
    "path": "lib/pbkdf2-sha256.cpp",
    "chars": 31111,
    "preview": "/*\n   this file is from https://github.com/kholia/PKCS5_PBKDF2, with additional code of hkdf_sha256\n\n *  FIPS-180-2 comp"
  },
  {
    "path": "lib/pbkdf2-sha256.h",
    "chars": 1027,
    "preview": "#pragma once\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\nvoid PKCS5_PBKDF2_HMAC_SHA256(unsigned char *p"
  },
  {
    "path": "libev/CVS/Entries",
    "chars": 1300,
    "preview": "/Changes/1.315/Wed Jun 21 14:42:30 2017//\n/LICENSE/1.11/Thu Jan 16 11:51:05 2014//\n/Makefile.am/1.9/Wed Dec 21 18:16:08 "
  },
  {
    "path": "libev/CVS/Repository",
    "chars": 6,
    "preview": "libev\n"
  },
  {
    "path": "libev/CVS/Root",
    "chars": 47,
    "preview": ":pserver:anonymous@cvs.schmorp.de/schmorpforge\n"
  },
  {
    "path": "libev/Changes",
    "chars": 27666,
    "preview": "Revision history for libev, a high-performance and full-featured event loop.\n\n\t- ANDROID => __ANDROID__ (reported by enh"
  },
  {
    "path": "libev/LICENSE",
    "chars": 2055,
    "preview": "All files in libev are\nCopyright (c)2007,2008,2009,2010,2011,2012,2013 Marc Alexander Lehmann.\n\nRedistribution and use i"
  },
  {
    "path": "libev/Makefile.am",
    "chars": 533,
    "preview": "AUTOMAKE_OPTIONS = foreign\n\nVERSION_INFO = 4:0:0\n\nEXTRA_DIST = LICENSE Changes libev.m4 autogen.sh \\\n\t     ev_vars.h ev_"
  },
  {
    "path": "libev/README",
    "chars": 2556,
    "preview": "libev is a high-performance event loop/event model with lots of features.\n(see benchmark at http://libev.schmorp.de/benc"
  },
  {
    "path": "libev/README.embed",
    "chars": 103,
    "preview": "This file is now included in the main libev documentation, see\n\n   http://cvs.schmorp.de/libev/ev.html\n"
  },
  {
    "path": "libev/Symbols.ev",
    "chars": 1095,
    "preview": "ev_async_send\nev_async_start\nev_async_stop\nev_backend\nev_break\nev_check_start\nev_check_stop\nev_child_start\nev_child_stop"
  },
  {
    "path": "libev/Symbols.event",
    "chars": 378,
    "preview": "event_active\nevent_add\nevent_base_dispatch\nevent_base_free\nevent_base_get_method\nevent_base_loop\nevent_base_loopexit\neve"
  },
  {
    "path": "libev/autogen.sh",
    "chars": 50,
    "preview": "#!/bin/sh\n\nautoreconf --install --symlink --force\n"
  },
  {
    "path": "libev/configure.ac",
    "chars": 406,
    "preview": "AC_INIT\n\norig_CFLAGS=\"$CFLAGS\"\n\nAC_CONFIG_SRCDIR([ev_epoll.c])\n\ndnl also update ev.h!\nAM_INIT_AUTOMAKE(libev,4.24)\nAC_CO"
  },
  {
    "path": "libev/ev++.h",
    "chars": 20449,
    "preview": "/*\n * libev simple C++ wrapper classes\n *\n * Copyright (c) 2007,2008,2010 Marc Alexander Lehmann <libev@schmorp.de>\n * A"
  },
  {
    "path": "libev/ev.3",
    "chars": 264817,
    "preview": ".\\\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.29)\n.\\\"\n.\\\" Standard preamble:\n.\\\" ========================="
  },
  {
    "path": "libev/ev.c",
    "chars": 129509,
    "preview": "/*\n * libev event processing core, watcher management\n *\n * Copyright (c) 2007,2008,2009,2010,2011,2012,2013 Marc Alexan"
  },
  {
    "path": "libev/ev.h",
    "chars": 29488,
    "preview": "/*\n * libev native API header\n *\n * Copyright (c) 2007,2008,2009,2010,2011,2012,2015 Marc Alexander Lehmann <libev@schmo"
  },
  {
    "path": "libev/ev.pod",
    "chars": 218072,
    "preview": "=encoding utf-8\n\n=head1 NAME\n\nlibev - a high performance full-featured event loop written in C\n\n=head1 SYNOPSIS\n\n   #inc"
  },
  {
    "path": "libev/ev_epoll.c",
    "chars": 9899,
    "preview": "/*\n * libev epoll fd activity backend\n *\n * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmorp"
  },
  {
    "path": "libev/ev_kqueue.c",
    "chars": 6810,
    "preview": "/*\n * libev kqueue backend\n *\n * Copyright (c) 2007,2008,2009,2010,2011,2012,2013 Marc Alexander Lehmann <libev@schmorp."
  },
  {
    "path": "libev/ev_poll.c",
    "chars": 4443,
    "preview": "/*\n * libev poll fd activity backend\n *\n * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmorp."
  },
  {
    "path": "libev/ev_port.c",
    "chars": 6404,
    "preview": "/*\n * libev solaris event port backend\n *\n * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmor"
  },
  {
    "path": "libev/ev_select.c",
    "chars": 8813,
    "preview": "/*\n * libev select fd activity backend\n *\n * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmor"
  },
  {
    "path": "libev/ev_vars.h",
    "chars": 6229,
    "preview": "/*\n * loop member variable declarations\n *\n * Copyright (c) 2007,2008,2009,2010,2011,2012,2013 Marc Alexander Lehmann <l"
  },
  {
    "path": "libev/ev_win32.c",
    "chars": 5320,
    "preview": "/*\n * libev win32 compatibility cruft (_not_ a backend)\n *\n * Copyright (c) 2007,2008,2009 Marc Alexander Lehmann <libev"
  },
  {
    "path": "libev/ev_wrap.h",
    "chars": 5510,
    "preview": "/* DO NOT EDIT, automatically generated by update_ev_wrap */\n#ifndef EV_WRAP_H\n#define EV_WRAP_H\n#define acquire_cb ((lo"
  },
  {
    "path": "libev/event.c",
    "chars": 9950,
    "preview": "/*\n * libevent compatibility layer\n *\n * Copyright (c) 2007,2008,2009,2010,2012 Marc Alexander Lehmann <libev@schmorp.de"
  },
  {
    "path": "libev/event.h",
    "chars": 6252,
    "preview": "/*\n * libevent compatibility header, only core events supported\n *\n * Copyright (c) 2007,2008,2010,2012 Marc Alexander L"
  },
  {
    "path": "libev/event_compat.h",
    "chars": 7449,
    "preview": "/*\n * Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>\n * Copyright (c) 2008      Marc Alexander Lehmann <li"
  },
  {
    "path": "libev/import_libevent",
    "chars": 3363,
    "preview": "#!/bin/sh\n\nLE=../libevent-1.4.3-stable\n\nif ! [ -e evbuffer.c ]; then\n   echo do not run this programm unless you know wh"
  },
  {
    "path": "libev/libev.m4",
    "chars": 1568,
    "preview": "dnl this file is part of libev, do not make local modifications\ndnl http://software.schmorp.de/pkg/libev\n\ndnl libev supp"
  },
  {
    "path": "libev/update_ev_c",
    "chars": 155,
    "preview": "#!/bin/sh -e\n\n(\n   sed -ne '1,\\%/\\* ECB.H BEGIN \\*/%p' ev.c\n   cat ~/src/libecb/ecb.h\n   sed -ne '\\%/\\* ECB.H END \\*/%,$"
  },
  {
    "path": "libev/update_ev_wrap",
    "chars": 506,
    "preview": "#!/bin/sh\n\n(\n   echo '#define VAR(name,decl) name'\n   echo '#define EV_GENWRAP 1'\n   cat ev_vars.h\n) | cc -E -o - - | pe"
  },
  {
    "path": "libev/update_symbols",
    "chars": 198,
    "preview": "#!/bin/sh\n\nmake ev.o event.o || exit\n\nnm ev.o           | perl -ne 'print \"$1\\n\" if /\\S+ [A-Z] (\\S+)/' > Symbols.ev\nnm e"
  },
  {
    "path": "log.cpp",
    "chars": 1373,
    "preview": "#include \"log.h\"\n#include \"misc.h\"\n\nint log_level = log_info;\n\nint enable_log_position = 0;\nint enable_log_color = 1;\n\nv"
  },
  {
    "path": "log.h",
    "chars": 1106,
    "preview": "\n#ifndef UDP2RAW_LOG_MYLOG_H_\n#define UDP2RAW_LOG_MYLOG_H_\n\n#include \"common.h\"\n\nusing namespace std;\n\n#define RED \"\\x1B"
  },
  {
    "path": "main.cpp",
    "chars": 3078,
    "preview": "#include \"common.h\"\n#include \"network.h\"\n#include \"connection.h\"\n#include \"misc.h\"\n#include \"log.h\"\n#include \"lib/md5.h\""
  },
  {
    "path": "makefile",
    "chars": 6223,
    "preview": "cc_cross=/home/wangyu/Desktop/arm-2014.05/bin/arm-none-linux-gnueabi-g++\ncc_local=g++\ncc_mips24kc_be=/toolchains/lede-sd"
  },
  {
    "path": "misc.cpp",
    "chars": 55148,
    "preview": "/*\n * misc.cpp\n *\n *  Created on: Sep 23, 2017\n *      Author: root\n */\n#include \"git_version.h\"\n#include \"common.h\"\n#in"
  },
  {
    "path": "misc.h",
    "chars": 5507,
    "preview": "/*\n * misc.h\n *\n *  Created on: Sep 23, 2017\n *      Author: root\n */\n\n#ifndef MISC_H_\n#define MISC_H_\n\n#include \"common"
  },
  {
    "path": "my_ev.cpp",
    "chars": 454,
    "preview": "#pragma GCC diagnostic push\n\n#pragma GCC diagnostic ignored \"-Wextra\"\n#pragma GCC diagnostic ignored \"-Wsign-compare\"\n#p"
  },
  {
    "path": "my_ev.h",
    "chars": 56,
    "preview": "#pragma once\n\n#include \"my_ev_common.h\"\n#include \"ev.h\"\n"
  },
  {
    "path": "my_ev_common.h",
    "chars": 410,
    "preview": "\n#define EV_STANDALONE 1\n#define EV_COMMON \\\n    void *data;   \\\n    unsigned long long u64;\n#define EV_COMPAT3 0\n\n//#in"
  },
  {
    "path": "network.cpp",
    "chars": 90364,
    "preview": "/*\n * network.cpp\n *\n *  Created on: Jul 29, 2017\n *      Author: wangyu\n */\n#include \"common.h\"\n#include \"network.h\"\n#i"
  },
  {
    "path": "network.h",
    "chars": 7391,
    "preview": "/*\n * network.h\n *\n *  Created on: Jul 29, 2017\n *      Author: wangyu\n */\n\n#ifndef UDP2RAW_NETWORK_H_\n#define UDP2RAW_N"
  },
  {
    "path": "pcap_wrapper.cpp",
    "chars": 4598,
    "preview": "#include <windows.h>\n#include <pcap_wrapper.h>\n#include <assert.h>\n#include <stdio.h>\nint (*pcap_loop)(pcap_t *, int, pc"
  },
  {
    "path": "pcap_wrapper.h",
    "chars": 3132,
    "preview": "#pragma once\n\n//#ifdef __cplusplus\n// extern \"C\" {\n//#endif\n\n//#include <sys/time.h>\n//#include <stdint.h>\n\nstruct bpf_p"
  },
  {
    "path": "server.cpp",
    "chars": 29947,
    "preview": "/*\n * server.cpp\n *\n *  Created on: Aug 29, 2018\n *      Author: root\n */\n\n#ifndef UDP2RAW_MP\n\n#include \"common.h\"\n#incl"
  },
  {
    "path": "third-party/luci-app-udp2raw/moved_to_new_repo",
    "chars": 43,
    "preview": "https://github.com/sensec/luci-app-udp2raw\n"
  },
  {
    "path": "third-party/udp2raw-cmake-makefile/CMakeLists.txt",
    "chars": 688,
    "preview": "cmake_minimum_required(VERSION 3.7)\nproject(udp2raw_tunnel)\n\nset(CMAKE_CXX_STANDARD 11)\nset_source_files_properties(lib/"
  },
  {
    "path": "third-party/udp2raw-openwrt-makefile/moved_to_new_repo",
    "chars": 42,
    "preview": "https://github.com/sensec/openwrt-udp2raw\n"
  }
]

About this extraction

This page contains the full source code of the wangyu-/udp2raw GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 99 files (1.5 MB), approximately 535.5k tokens, and a symbol index with 833 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!