一种不需要客户端ip的命令行远程工具

这篇具有很好参考价值的文章主要介绍了一种不需要客户端ip的命令行远程工具。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

项目地址:Academy remote system: 一种不需要客户端ip的命令行远程工具 - Gitee.com

项目介绍:

传统的远程命令行工具如ssh,scp都需要目标服务器的ip才可以连接。

我设计的这款命令行远程工具可以基于多个中间服务器进行远程,而不需要设置目标ip。

部分代码(20240317年更新)

academy_client-aca.c:

#include <stdio.h>
#include "yamlreader.h"
#include "codereader.h"
#include <string.h>
//#define DEBUGMODE
void show_copyright(void){
    printf("@copyright2024 Anchengan\n");
}
void show_help(void){
    printf("Help document for aca software:\n");
    printf("aca [authkey of remote client] [path to settings.yaml] [password of remote client]\n");
    printf("aca listenmode [path to settings.yaml]\n");
}
int is_path_in_ld_library_path(const char *path_to_check) {
    const char *ld_library_path = getenv("LD_LIBRARY_PATH");
    if (ld_library_path == NULL) {
        // 如果LD_LIBRARY_PATH未设置,则直接返回0(不在其中)
        return 0;
    }

    // 分割LD_LIBRARY_PATH并检查每个路径
    char *path_copy = strdup(ld_library_path); // 复制环境变量值
    char *token = strtok(path_copy, ":");
    while (token != NULL) {
        // 比较当前路径和要检查的路径
        if (strcmp(token, path_to_check) == 0) {
            free(path_copy); // 释放内存
            return 1; // 找到路径,返回1
        }
        token = strtok(NULL, ":"); // 继续查找下一个路径
    }

    free(path_copy); // 释放内存
    return 0; // 未找到路径,返回0
}
char* remove_char(const char* str, char c) {
    int count = 0;
    for (const char* p = str; *p; p++) {
        if (*p != c) {
            count++;
        }
    }

    // 分配足够的空间来存储新字符串
    char* result = (char*)malloc(count + 1);  // +1 为 '\0'
    if (!result) {
        return NULL;  // 内存分配失败
    }

    int i = 0;
    for (const char* p = str; *p; p++) {
        if (*p != c) {
            result[i++] = *p;
        }
    }
    result[i] = '\0';  // 确保新字符串以 '\0' 结尾

    return result;
}
int main(int argc, char *argv[]) {
    // 打印传递的参数
    if(argc-1==0){
	show_copyright();
        printf("Enter -h or --help after aca for help.\n");
	printf("Example:\naca -h\naca --help\n");
	return 0;
    }
    for(int i=1;i<=argc-1;i++){
        if(strcmp(argv[i],"-h")==0 || strcmp(argv[i],"--help")==0){
            show_copyright();
            show_help();
            return 0;
        }
    }
    if(argc-1>3){
        printf("Unknown usage of aca...\n");
        show_help();
        return 0;
    }
    int yamllength=strlen(argv[2]);
    if(yamllength<5 || argv[2][yamllength-5]!='.' || argv[2][yamllength-4]!='y' || argv[2][yamllength-3]!='a' || argv[2][yamllength-2]!='m' || argv[2][yamllength-1]!='l'){
        printf("Please check your path to settings.yaml!\n");
        printf("Example:./settings.yaml\n");
        show_help();
	return 0;
    }
    int islistenmode=0;
    if (strcmp(argv[1],"listenmode")==0){
        if(argc-1>2){
            printf("Unknown usage of aca...\n");
            show_help();
            return 0;
        }
	printf("listenmode setup successfully...\n");
	islistenmode=1;
    }else{
        printf("your authkey of remote client is:%s\n",argv[1]);
    }
    printf("setting env...\n");
    int env_return_value;
    const char *path_to_check = "./"; // 要检查的路径  
    const char *bashrc_path = getenv("HOME"); // 获取用户主目录
    if (bashrc_path == NULL) {
        perror("Error getting HOME environment variable");
        return EXIT_FAILURE;
    }

    // 拼接.bashrc文件的完整路径
    char full_path[1024];
    snprintf(full_path, sizeof(full_path), "%s/.bashrc", bashrc_path);

    // 打开.bashrc文件
    FILE *file = fopen(full_path, "r");
    if (file == NULL) {
        perror("Error opening ~/.bashrc");
        return EXIT_FAILURE;
    }

    // 要搜索的内容
    const char *search_content = "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./";
    char line[1024]; // 假设每行不会超过1023个字符

    // 逐行读取并搜索内容
    int found = 0; // 标记是否找到内容
    while (fgets(line, sizeof(line), file)) {
        if (strstr(line, search_content) != NULL) {
#ifdef DEBUGMODE
            printf("Found the content in ~/.bashrc: %s", line);
#endif
	    found = 1; // 找到内容,设置标记
            break; // 如果只需要找到一次就退出循环
        }
    }

    

    // 关闭文件
    fclose(file);

    if (!is_path_in_ld_library_path(path_to_check) && !found) {  
          
 
        // 使用system()函数运行命令行命令
        env_return_value = system("echo 'export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./' >> ~/.bashrc");

        // 检查命令的退出码
#ifdef DEBUGMODE

        if (env_return_value == -1) {
            // system()函数调用失败
            // 在这种情况下,你可以查看errno来获取错误详情(需要包含errno.h头文件)
            perror("system() failed");
        } else if (WIFEXITED(env_return_value)) {
            // 命令正常退出,WEXITSTATUS(env_return_value)可以获取命令的退出状态
            printf("Command exited with status %d\n", WEXITSTATUS(env_return_value));
        } else if (WIFSIGNALED(env_return_value)) {
            // 命令因为接收到信号而终止,WTERMSIG(env_return_value)可以获取信号的编号
            printf("Command terminated by signal %d\n", WTERMSIG(env_return_value));
        }
#endif
        printf("env set successfully...\n");
        printf("please run: source ~/.bashrc\n");
	return 0;
    }else if(!is_path_in_ld_library_path(path_to_check) && found){
        printf("please run: source ~/.bashrc\n");
	return 0;
    }
    #include "libsender.h"
    #include "libreceiver.h"
    printf("your path to settings.yaml is:%s\n",argv[2]);    
    
    printf("Reading settings.yaml...\n");
    struct item_ret* yaml_data = get_item(argv[2]);
    struct ip* ip_reader;
    struct port* port_reader;
    ip_reader=yaml_data->ip_items;
    port_reader=yaml_data->port_items;
    char mac_device[20];

    char c = ':';   
    strcpy(mac_device,yaml_data->mac_device);
    int iplength = 0;
    struct ip* ip_pin = ip_reader;
    while (ip_pin != NULL) {
        iplength++;
        ip_pin = ip_pin->next;
    }
    
    char send_ip_info[iplength*100];
    char send_port_info[iplength*100];
    while (ip_reader != NULL){
        printf("ip:%s\n", ip_reader->ip);
	strcat(send_ip_info,ip_reader->ip);
	strcat(send_ip_info,"-");
        ip_reader = ip_reader->next;
	for(int i=0;i<2;i++){
            printf("port:%s\n", port_reader->port);
	    strcat(send_port_info,port_reader->port);
	    strcat(send_port_info,"-");
            port_reader = port_reader->next;
        }
    }
    printf("settings.yaml read completed...\n");
    if(islistenmode){
	//waiting for connection...
        printf("Getting connecting code of this device...\n");
	struct device_ret* device_data=get_device_code(mac_device);
        char* device_code=device_data->mac_device;
	char* address_code=device_data->mac_address;
        printf("Connecting code of this device is:%s\n",device_code);
        char* password = remove_char(address_code, c);
	printf("Your password is:%s\n",password);
        Receiver(device_code,password,send_ip_info,send_port_info);
    }else{
	Sender(argv[1],argv[3],send_ip_info,send_port_info);
        //connecting...
    }
    return 0; 
}

academy_server-acade.go:文章来源地址https://www.toymoban.com/news/detail-841889.html

package main
import (
 "fmt"
 "bufio"
 "net"
 "sync"
 "io/ioutil"
 "log"
 "os"
 "strconv"
 "gopkg.in/yaml.v2"
)
type client struct {
        conn     net.Conn
        connid string
        name     string
        messages chan  string
}
type Message struct {
    conn net.Conn
    connid string
    SenderName string
    Content    string
}
var (
        entering = make(chan client)
        leaving  = make(chan client)
        messages = make(chan Message) // 所有接收的消息
)
type Config struct {
 Database struct {
 Host     string `yaml:"host"`
 Port     int    `yaml:"port"`
 Port2    int    `yaml:"port2"`
 } `yaml:"database"`
}
func broadcast() {
    clients := make(map[string]client) // 键是客户端的名称,值是客户端结构体实例

    for {
        select {
        case msg := <-messages:
            // 将消息广播给除了发送者以外的所有客户端
            for _,cli := range clients {
                if cli.name != msg.SenderName && cli.connid==msg.connid {
                   cli.messages<- msg.Content
                }
            }
        case newClient := <-entering:
            clients[newClient.name] = newClient
        case leavingClient := <-leaving:
        delete(clients, leavingClient.name)
           close(leavingClient.messages)
        }
    }
}
func handleConn(conn net.Conn,connid string) {
        input := bufio.NewScanner(conn)
        var wg sync.WaitGroup
        // 创建一个新的客户端
        ch := make(chan string,1)  // 客户端的消息通道
        go clientWriter(conn, ch)
        cli := client{conn: conn, connid:connid,name: conn.RemoteAddr().String(), messages: ch}
        entering <- cli
        fmt.Println(cli.name)
        wg.Add(1)
        go func() {
                defer wg.Done()
                for input.Scan() {
                        messages <-Message{SenderName: cli.name, Content: input.Text(),conn:conn,connid:connid} // cli.name + ": " + input.Text()
                        _, err := conn.Write([]byte("Received your message\n"))
                         if err != nil {
                                fmt.Println("Error writing to connection:", err.Error())
                                break
                         }
                }
        }()
        wg.Wait()
        leaving <- cli
        conn.Close()
}
func clientWriter(conn net.Conn, ch <-chan string) {

        for msg := range ch {
                fmt.Fprintln(conn, msg) // 注意:网络写入应该有错误处理
        }
}

func main() {
	argCount := len(os.Args) - 1
	if argCount == 0 {
		fmt.Println("没有传递任何参数。")
		fmt.Println("acade -h")
		fmt.Println("acade --help")
		os.Exit(1) // 使用非零状态码退出,表示错误  
	}

	// 如果参数数量不符合预期(例如,你需要恰好2个参数),提前返回  
	if argCount != 1 {
		fmt.Printf("需要1个参数,但传递了%d个参数。\n", argCount)
		os.Exit(1) // 使用非零状态码退出,表示错误  
	}

	yamlfilename:=os.Args[1]
	if yamlfilename=="-h" || yamlfilename=="--help"{
            fmt.Println("acade [path to settings.yaml]")
	    os.Exit(0)
	}
         // 读取YAML文件内容  
         yamlFile, err := ioutil.ReadFile(yamlfilename)
        if err != nil {
            log.Fatalf("无法读取YAML文件: %v", err)
         }
         // 解析YAML内容  
         var config Config
         err = yaml.Unmarshal(yamlFile, &config)
         if err != nil {
             log.Fatalf("无法解析YAML内容: %v", err)
         }
         // 输出解析后的内容  
         fmt.Printf("Host: %s\n", config.Database.Host)
         fmt.Printf("Port: %d\n", config.Database.Port)
	 fmt.Printf("Port2: %d\n", config.Database.Port2)
	 Host:=config.Database.Host
	 Port:=strconv.Itoa(config.Database.Port)
	 Port2:=strconv.Itoa(config.Database.Port2)
	 listener, err := net.Listen("tcp",Host+":"+Port)
	 if err != nil {
                fmt.Println(err)
                return
        }
	listener2, err2 := net.Listen("tcp",Host+":"+Port2)
        if err2 != nil {
                fmt.Println(err2)
                return
        }
        go broadcast()
        go func(){
        for {
                conn, err := listener.Accept()
                if err != nil {
                        fmt.Println(err)
                        continue
                }
                go handleConn(conn,"1")
            }
        }()
        go func(){
            for{
                conn2, err2 := listener2.Accept()
                if err2 != nil {
                        fmt.Println(err2)
                        continue
                }
                go handleConn(conn2,"2")
            }
        }()
        for{}
	// 程序正常执行完毕,使用零状态码退出  
	os.Exit(0)
}

到了这里,关于一种不需要客户端ip的命令行远程工具的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java 获取客户端IP

      ps:代码引用于 JAVA获取客户端IP地址-CSDN博客 https://blog.csdn.net/m0_71867302/article/details/129683061?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170738691916800226562378%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257Drequest_id=170738691916800226562378biz_id=0utm_medium=distribute.pc_search_result.none-task-bl

    2024年02月22日
    浏览(31)
  • 获取客户端请求IP及IP所属城市

    添加pom依赖       dependency             groupIdorg.lionsoul/groupId             artifactIdip2region/artifactId             version2.6.5/version         /dependency public class IpUtil {     private static Searcher searcher;     private static final String DEFAULT_UNKNOWN=\\\"unknown\\\";     private static final int IP_MIN_LENGT

    2024年02月08日
    浏览(38)
  • SSH客户端连接远程服务器

    目录 一、什么是客户端连接远程服务器 二、什么是服务端连接远程服务器 三、查看网络信息 1、图形程序查看网络信息 2、命令查看网络信息 四、SSH客户端(Linux) 五、SSH客户端(windows) 六、SSH远程服务器 发起连接的一方,计算机或设备(称为客户端)与另一个计算机或

    2024年02月16日
    浏览(41)
  • kubernetes获取客户端真实ip

    大部分的业务场景都需要获取客户端的ip来审计或采取措施,文章从nodeport暴露方式获取真实ip到ingress-nginx获取真实ip 初学者用k8s创建时暴露方式一般采用nodeport,这样方式暴露导致应用负载和访问者并不是同一段网络,当web服务获取客户端ip的时候会发现获取到的ip是k8s网关的

    2024年02月01日
    浏览(33)
  • SQLServer如何获取客户端IP

    SQLServer如何获取客户端IP 很多用户询问如何通过SQLServer获取客户端IP从而定位一些问题,比如链接泄露,其实主要是利用几个相关视图,如下给出一些SQL方便用户排查 当前链接 所有链接 查看更详细的链接参数配置 ------获取

    2024年02月09日
    浏览(30)
  • nginx-获取客户端IP地址

    上有服务器与客户端中间是有nginx代理服务器的,上游服务器如何获取客户端真实ip地址? nginx代理服务器设置X-Forwarded-For的header参数,代理服务器通过remote_addr获取客户端ip地址,将ip地址写入nginx代理服务器的X-Forwarded-For中, 上游服务端通过在nginx的这个参数拿到客户端IP地

    2024年02月11日
    浏览(36)
  • nginx获取客户端真实ip

    在nginx中获取客户端真实IP的方法有多种,以下是其中两种常用的方法: 使用nginx的access_log模块记录请求日志,并在日志中包含客户端的真实IP信息。例如: 在上述配置中,通过使用http_x_forwarded_for字段来获取客户端的真实IP地址。如果该字段不存在或不合法,则使用remote_ad

    2024年02月16日
    浏览(38)
  • JAVA获取客户端IP地址

    2024年02月16日
    浏览(36)
  • nginx 获取客户端真实IP

    网站接入Web应用防火墙WAF(Web Application Firewall)后,访问请求在到达源站服务器之前,需要经过WAF的代理转发。这种情况下,源站服务器可以通过解析回源请求中的X-Forwarded-For记录,获取客户端的真实IP。 WAF在将客户端的访问请求转发到下一环节的服务器时,会在HTTP的请求头

    2023年04月09日
    浏览(37)
  • 获取客户端真实IP的方法

    获取请求的IP很简单,可以直接使用request.getRemoteAddr()直接获取。但由于请求在转发到接口前,会经过大量的反向代理,例如流程图中,至少要经过Nginx后,请求才会转发到接口,因此需要对请求接口的IP做处理,提取客户端真实IP地址。 配置Nginx的配置文件,需要反向代理服务

    2024年02月16日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包