1

我写了简单的 wlan manager 工具。它使用 system() 运行 iproute2/iw/wpa_supplicant/dhcpcd 以连接到接入点。现在我想将它改进为比运行外部命令更好的方法。有人说你永远不应该使用 system() 因为在 C 中总是有更好的方法。

我探索了 wicd,似乎它纯粹是通过执行和解析外部命令来工作的。NetworkManager 比较复杂,似乎使用了一些其他的方法。我知道最好使用外部库来完成。如果是这种情况,我想知道我应该寻找哪些库。作为旁注,很高兴听到我在代码设计中做出了糟糕的选择。

ccwm.c

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>

char **global_argv;

void usage() {
    printf("Usage: %s [options] -o/-a/-w/-W\n\n", global_argv[0]);

    puts("-h              Show help\n");

    puts("-i [interface]  Set interface (default: wlan0)");
    puts("-e [ssid]       Set SSID");
    puts("-f [freq]       Set frequency");
    puts("-k [key]        Set key/passphrase\n");

    puts("-s              Scan access points");
    puts("-S              Scan access points verbosely");
    puts("-I              Show interface info\n");

    puts("-o              Connect to ESS access point");
    puts("-a              Connect to IBSS access point");
    puts("-w              Connect to WEP encrypted access point");
    puts("-W              Connect to WPA encrypted access point");
}

void ifup(char *ifname) {
    char *cmdline = "";
    cmdline = malloc(36);
    size_t s1 = strlen(ifname);
    snprintf(cmdline, s1+16, "ip link set %s up", ifname);
    system(cmdline);
    free(cmdline);
}

void scan(char *ifname, int type) {
    char *cmdline = "";
    cmdline = malloc(33);
    size_t s1 = strlen(ifname);

    if (type == 0) {
        snprintf(cmdline, s1+31, "iw dev %s scan | awk -f scan.awk", ifname);
        system(cmdline);
    }
    else {
        snprintf(cmdline, s1+13, "iw dev %s scan", ifname);
        system(cmdline);
    }

    free(cmdline);
}

void info(char *ifname) {
    char *cmdline = "";
    cmdline = malloc(43);
    size_t s1 = strlen(ifname);
    snprintf(cmdline, s1+13, "iw dev %s info", ifname);
    system(cmdline);
    snprintf(cmdline, s1+13, "iw dev %s link", ifname);
    system(cmdline);
    snprintf(cmdline, s1+23, "iw dev %s get power_save", ifname);
    system(cmdline);
    free(cmdline);
}

void connect(char *ifname, char *essid, char *freq, char *key, int type) {
    system("killall dhcpcd 2> /dev/null");
    char *cmdline = "";
    cmdline = malloc(100);
    size_t s1 = strlen(ifname);
    size_t s2 = strlen(essid);
    size_t s3 = strlen(freq);
    size_t s4 = strlen(key);

    if (type < 3) {
        snprintf(cmdline, s1+25, "iw dev %s set type managed", ifname);
        system(cmdline);
    }
    else {
        snprintf(cmdline, s1+22, "iw dev %s set type ibss", ifname);
        system(cmdline);
    }

    if (type == 0) {
        snprintf(cmdline, s1+s2+20, "iw dev %s connect -w %s", ifname, essid);
        system(cmdline);
        snprintf(cmdline, s1+8, "dhcpcd %s", ifname);
        system(cmdline);
    }
    else if (type == 1) {
        snprintf(cmdline, s1+s2+s4+26, "iw dev %s connect -w %s keys %s", ifname, essid, key);
        system(cmdline);
        snprintf(cmdline, s1+8, "dhcpcd %s", ifname);
        system(cmdline);
    }
    else if (type == 2) {
        snprintf(cmdline, s1+s2+s4+45, "wpa_supplicant -B -i %s -c <(wpa_passphrase %s %s)",
                                    ifname, essid, key);
        system(cmdline);
        snprintf(cmdline, s1+8, "dhcpcd %s", ifname);
        system(cmdline);
    }
    else {
        snprintf(cmdline, s1+s2+s3+20, "iw dev %s ibss join %s %s", ifname, essid, freq);
        system(cmdline);
        snprintf(cmdline, s1+8, "dhcpcd %s", ifname);
        system(cmdline);
    }

    free(cmdline);
}

int main(int argc, char *argv[]) {
    global_argv = argv;
    int opt;
    char *ifname = "wlan0";
    char *essid = "";
    char *freq = "";
    char *key = "";

    uid_t uid=getuid();
    if (uid != 0) {
        puts("\nThis program needs to be run with root privileges!\n");
    }

    if (argc <= 1) {
        usage();
    }

    while ((opt = getopt(argc, argv, "IsSowWahi:e:f:k:")) != -1) {
        switch (opt) {
            case 'i':
                ifname = optarg;
                break;
            case 'e':
                essid = optarg;
                break;
            case 'f':
                freq = optarg;
                break;
            case 'k':
                key = optarg;
                break;
            case 'I':
                ifup(ifname);
                info(ifname);
                break;
            case 's':
                ifup(ifname);
                scan(ifname, 0);
                break;
            case 'S':
                ifup(ifname);
                scan(ifname, 1);
                break;
            case 'o':
                if (essid[0] == '\0') {
                    printf("You must specify ssid!\n");
                    break;
                }
                ifup(ifname);
                connect(ifname, essid, freq, key, 0);
                break;
            case 'w':
                if (essid[0] == '\0' || key[0] == '\0') {
                    printf("You must specify ssid and key!\n");
                    break;
                }
                ifup(ifname);
                connect(ifname, essid, freq, key, 1);
                break;
            case 'W':
                if (essid[0] == '\0' || key[0] == '\0') {
                    printf("You must specify ssid and passphrase!\n");
                    break;
                }
                ifup(ifname);
                connect(ifname, essid, freq, key, 2);
                break;
            case 'a':
                if (essid[0] == '\0' || freq[0] == '\0') {
                    printf("You must specify ssid and freq!\n");
                    break;
                }
                ifup(ifname);
                connect(ifname, essid, freq, key, 3);
                break;
            case 'h':
            default:
                usage();
                break;
        }
    }

    return 0;
}

扫描.awk

/^BSS / {
    MAC = $2
    wifi[MAC]["enc"] = "Open"
}
$1 == "SSID:" {
    wifi[MAC]["SSID"] = $2
}
$1 == "freq:" {
    wifi[MAC]["freq"] = $2
}
$1 == "signal:" {
    wifi[MAC]["sig"] = $2 " " $3
}
$1 == "capability:" {
    wifi[MAC]["type"] = $2
}
$1 == "WPA:" {
    wifi[MAC]["enc"] = "WPA"
}
$1 == "WEP:" {
    wifi[MAC]["enc"] = "WEP"
}
END {
    for (w in wifi) {
        if ( i++ > 0 ) { printf "\n" }
        printf "SSID: %s\nType: %s\nFrequency: %s\nSignal: %s\nEncryption: %s\n"\
        ,wifi[w]["SSID"],wifi[w]["type"],wifi[w]["freq"],wifi[w]["sig"],wifi[w]["enc"]
    }
}
4

0 回答 0