-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
提供一个http服务,响应返回请求的IP地址,配合ddns使用
- Loading branch information
Showing
5 changed files
with
192 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
name: Publish Version | ||
on: | ||
push: | ||
tags: | ||
- 'v*' | ||
|
||
env: | ||
DOCKERHUB_REPO: evlan/http_echo_ip | ||
APP_VERSION: ${{ github.ref_name }} | ||
|
||
jobs: | ||
pulish-docker-images: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v4 | ||
|
||
- name: Set up QEMU | ||
uses: docker/setup-qemu-action@v3 | ||
|
||
- name: Set up Docker Buildx | ||
uses: docker/setup-buildx-action@v3 | ||
|
||
- name: Login to Docker Hub | ||
uses: docker/login-action@v3 | ||
with: | ||
username: ${{ secrets.DOCKERHUB_USERNAME }} | ||
password: ${{ secrets.DOCKERHUB_TOKEN }} | ||
|
||
- name: Build and push | ||
uses: docker/build-push-action@v5 | ||
with: | ||
push: true | ||
platforms: linux/amd64,linux/arm64 | ||
tags: ${{ env.DOCKERHUB_REPO }}:latest,${{ env.DOCKERHUB_REPO }}:${{ env.APP_VERSION }} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
name: Release | ||
|
||
on: | ||
push: | ||
tags: | ||
- 'v*' | ||
|
||
jobs: | ||
create-release: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: taiki-e/create-gh-release-action@v1 | ||
with: | ||
token: ${{ secrets.RELEASE_TOKEN }} | ||
|
||
upload-assets: | ||
needs: create-release | ||
strategy: | ||
matrix: | ||
include: | ||
- target: x86_64-unknown-linux-gnu | ||
os: ubuntu-latest | ||
- target: x86_64-apple-darwin | ||
os: macos-latest | ||
- target: x86_64-pc-windows-msvc | ||
os: windows-latest | ||
runs-on: ${{ matrix.os }} | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: taiki-e/upload-rust-binary-action@v1 | ||
with: | ||
bin: http_echo_ip | ||
target: ${{ matrix.target }} | ||
tar: unix | ||
zip: windows | ||
token: ${{ secrets.RELEASE_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
[package] | ||
name = "http_echo_ip" | ||
version = "1.0.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
chrono = "0.4.37" | ||
clap = { version = "4.5.4", features = ["derive"] } | ||
regex = "1.10.4" | ||
tokio = { version = "1.37.0", features = ["io-util", "net", "rt", "rt-multi-thread", "macros"] } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
FROM rust:alpine AS builder | ||
|
||
WORKDIR /usr/src/myapp | ||
|
||
COPY . . | ||
|
||
RUN apk update && apk add musl musl-dev && cargo build --release | ||
|
||
FROM alpine:latest | ||
|
||
WORKDIR /usr/src/myapp | ||
|
||
COPY --from=builder /usr/src/myapp/target/release/http_echo_ip . | ||
|
||
ENTRYPOINT ["./http_echo_ip"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
use std::collections::HashMap; | ||
use chrono::{FixedOffset, Local}; | ||
use clap::Parser; | ||
use regex::Regex; | ||
use std::error::Error; | ||
use std::sync::{Arc, Mutex}; | ||
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; | ||
use tokio::net::{TcpListener, TcpStream}; | ||
|
||
#[derive(Parser, Debug)] | ||
#[command(version, about, long_about = None)] | ||
struct Args { | ||
/// 监听地址 | ||
#[arg(short, long, default_value = "127.0.0.1")] | ||
listen: String, | ||
|
||
/// 监听端口号 | ||
#[arg(short, long, default_value_t = 80)] | ||
port: usize, | ||
} | ||
|
||
impl Args { | ||
fn to_string(&self) -> String { | ||
format!("{}:{}", self.listen, self.port) | ||
} | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() -> Result<(), Box<dyn Error>> { | ||
let args = Args::parse(); | ||
let server = TcpListener::bind(args.to_string()).await?; | ||
println!("{}Listening on: {}", get_time(), args.to_string()); | ||
|
||
let cache_times = Arc::new(Mutex::new(HashMap::new())); | ||
|
||
//正则从header读 nginx转发带的 | ||
let forwarded_for_regex = Regex::new(r"X-Forwarded-For:\s*(?P<ip>(?:\d{1,3}\.){3}\d{1,3})").unwrap(); | ||
let real_ip_regex = Regex::new(r"X-Real-IP:\s*(?P<ip>(?:\d{1,3}\.){3}\d{1,3})").unwrap(); | ||
let remote_host_regex = Regex::new(r"REMOTE-HOST:\s*(?P<ip>(?:\d{1,3}\.){3}\d{1,3})").unwrap(); | ||
let regexes = Arc::new(Vec::from([forwarded_for_regex, real_ip_regex, remote_host_regex])); | ||
|
||
loop { | ||
let regexes = Arc::clone(®exes); | ||
let cache_times = Arc::clone(&cache_times); | ||
let (stream, _) = server.accept().await?; | ||
tokio::spawn(async move { | ||
if let Err(e) = process(stream, regexes, cache_times).await { | ||
println!("failed to process connection; error = {}", e); | ||
} | ||
}); | ||
} | ||
} | ||
|
||
async fn process(mut stream: TcpStream, regexes: Arc<Vec<Regex>>, cache_times: Arc<Mutex<HashMap<String, usize>>>) -> Result<(), Box<dyn Error>> { | ||
//直接读链接的地址 | ||
let mut ip = stream.peer_addr()?.ip().to_string(); | ||
let mut http_request = BufReader::new(&mut stream).lines(); | ||
|
||
//接收数据从header再读一遍 | ||
while let Some(line) = http_request.next_line().await? { | ||
if line.len() == 0 { | ||
break; | ||
} | ||
for regex in regexes.iter() { | ||
if let Some(capture) = regex.captures(&line) { | ||
if let Some(v) = capture.name("ip") { | ||
ip = v.as_str().to_string(); | ||
} | ||
} | ||
} | ||
} | ||
stream.write_all(format!("HTTP/1.1 200 OK\r\nContent-Length: {}\r\nContent-Type: text/html; charset=utf-8\r\n\r\n{}\r\n", ip.len(), ip).as_bytes()).await?; | ||
let mut map = cache_times.lock().unwrap(); | ||
let mut times = 1; | ||
match map.get_mut(&ip) { | ||
None => { | ||
map.insert(ip.clone(), 1); | ||
} | ||
Some(v) => { | ||
*v += 1; | ||
times = *v; | ||
} | ||
} | ||
println!("{}Request from: {:<15}({})", get_time(), ip, times); | ||
Ok(()) | ||
} | ||
|
||
fn get_time() -> String { | ||
let offset = FixedOffset::east_opt(8 * 60 * 60).unwrap(); | ||
let shanghai_time = Local::now().with_timezone(&offset); | ||
shanghai_time.format("[%Y-%m-%d %H:%M:%S%.3f]").to_string() | ||
} |