helper.c.svn-base

来自「wipfw 是windows下的网络控制工具」· SVN-BASE 代码 · 共 386 行

SVN-BASE
386
字号
/* Copyright (c) 2004-2006 Ruslan Staritsin, Vlad Goncharov
 *
 * Redistribution and use in source forms, with and without modification,
 * are permitted provided that this entire comment appears intact.
 *
 * Redistribution in binary form may occur without any restrictions.
 * Obviously, it would be nice if you gave credit where credit is due
 * but requiring it would be too onerous.
 *
 * This software is provided ``AS IS'' without any warranties of any kind.
 */

#include <windows.h>
#include <winsock2.h>
#include <winioctl.h>
#include <iphlpapi.h>
#include <process.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>

#include "helper.h"
#include "stdint.h"
#include "wipfw.h"
#include "win32.h"

static unsigned __stdcall   iflist_thread(void *param);
static unsigned __stdcall   iflist_thread2(void *param);
static HANDLE    g_threads[2];
static SOCKET    g_socket;
static int g_sw;

#define BUF_SIZE    (640 * 256)

BOOL
start(const char *config, BOOL exec)
{
    TCHAR szPath[MAX_PATH];
    unsigned int tid,tid2;
    int status;
    char exestr[MAX_PATH];
    char cmdline[1024];

    InitializeCriticalSection(&cs);

    // setup information about interfaces
    status = update_if_info(TRUE);
    if (status != 0) {
        fprintf(stderr, "start: update_if_info: %d\n", status);
        DeleteCriticalSection(&cs);
        return FALSE;
    }

    GetModuleFileName(0, szPath, MAX_PATH);
    *strrchr(szPath, '\\') = 0;
    SetCurrentDirectory ( szPath );

    if (exec == TRUE) {
        // execute command script
        if (_snprintf(cmdline, sizeof(cmdline), "cmd.exe /c \"%s\"", config) < 0) {
            fprintf(stderr, "start: Command line to execute too long!");
            // continue anyway
        }
        else {
            // execute startup script
            WinExec(cmdline, SW_HIDE);
        }
    }

    g_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
    if (g_socket == INVALID_SOCKET) {
        fprintf(stderr, "start: socket: %d\n", WSAGetLastError());
        DeleteCriticalSection(&cs);
        return FALSE;
    }

    g_threads[0] = (HANDLE)_beginthreadex(NULL, 0, iflist_thread, NULL, 0, &tid);
    g_threads[1] = (HANDLE)_beginthreadex(NULL, 0, iflist_thread2, NULL, 0, &tid2);
    if ((g_threads[0] == NULL) || (g_threads[1] == NULL)) {
        fprintf(stderr, "start: _beginthreadex: %d\n", errno);
        closesocket(g_socket);
        DeleteCriticalSection(&cs);
        return FALSE;
    }

    return TRUE;
}

void
stop(void)
{
    closesocket(g_socket);
    g_sw = 1;
}

void
wait(void)
{
    WaitForMultipleObjects(2, g_threads, FALSE, INFINITE);
    if (g_threads[0] != NULL)
        CloseHandle(g_threads[0]);
    if (g_threads[1] != NULL)
        CloseHandle(g_threads[1]);
    DeleteCriticalSection(&cs);
}

void
if_check()
{
    IP_ADAPTER_INFO *ipi, *ai;
    DWORD status;
    ULONG size;
    ULONG idx = 0;
    static ULONG old_idx;

    GetAdaptersInfo(NULL, &size);
    ipi = malloc(size);
    status = GetAdaptersInfo(ipi, &size);

    if (status == ERROR_SUCCESS && ipi != NULL) {
        /* get the 'checksum' of indexes */
        for (ai = ipi; ai != NULL; ai = ai->Next)
            idx += ai->Index;

        /* if checksum changed, update adapters info */
        if (idx != old_idx) {
            old_idx = idx;
            update_if_info(TRUE);
        }
        free(ipi);
    }

    return;
}

unsigned __stdcall
iflist_thread(void *param)
{
    while ( !g_sw ) {
        Sleep(5000);
        if_check();
    }
    return 0;
}

unsigned __stdcall
iflist_thread2(void *param)
{
    DWORD n;

    for (;;) {
        Sleep(1000);
        if (WSAIoctl(g_socket, SIO_ADDRESS_LIST_CHANGE, NULL, 0, NULL, 0, &n, NULL, NULL) == SOCKET_ERROR) {
            fprintf(stderr, "WSAIoctl: %d\n", WSAGetLastError());
            break;
        }
        update_if_info(TRUE);
    }
    return 0;
}

int idx_byguid(char *guid, char *name)
{
    TCHAR PrePath[] = _T("SYSTEM\\CurrentControlSet\\Control\\Network\\"\
                         "{4D36E972-E325-11CE-BFC1-08002BE10318}\\");
    TCHAR Path[MAX_PATH];
    TCHAR szName[MAX_PATH];
    DWORD size = MAX_PATH;
    HKEY hBaseKey = NULL;
    DWORD i = 0;

    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
                     PrePath,
                     0,
                     KEY_READ,
                     &hBaseKey) != ERROR_SUCCESS)
        return 0;

    while (RegEnumKeyEx(hBaseKey, ++i, szName, &size, \
                        NULL, NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS) {
        if (!strncmp(szName, guid, size)) {
            RegCloseKey(hBaseKey);

            wsprintf(Path, _T("%s%s%s"), PrePath, szName, _T("\\Connection"));

            if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, Path, 0, KEY_READ, &hBaseKey) == ERROR_SUCCESS)
                if (RegQueryValueEx(hBaseKey, _T("Name"),0, NULL, Path, &size)== ERROR_SUCCESS)
                    strncpy(name, Path, 41);

            return i;
        }
        size = MAX_PATH;
    }

    RegCloseKey(hBaseKey);
    return 0;
}

int
update_if_info(BOOL cfile)
{
    HANDLE device = INVALID_HANDLE_VALUE;
    DWORD n, ie_buf_size, last_ie_offset;
    IP_ADAPTER_INFO *ai;
    IP_ADDR_STRING *as;
    char *buf = NULL, *ie_buf = NULL, *ifnam = NULL;
    int status, i;
    unsigned short last_units[sizeof(g_if_types) / sizeof(*g_if_types)];
    struct ip_fw_iflist_entry *last_ie;
    struct sockaddr_in *sin;

    if (cfile == TRUE)
        EnterCriticalSection(&cs);

    buf = malloc(BUF_SIZE);
    if (buf == NULL) {
        perror("malloc");
        goto done;
    }

    memset(last_units, 0, sizeof(last_units));

    // first, append information about loopback adapter

    ie_buf = (char *)malloc(sizeof(struct ip_fw_iflist_entry) + sizeof(struct sockaddr_in));
    if (ie_buf == NULL) {
        perror("malloc");
        goto done;
    }

    last_ie = (struct ip_fw_iflist_entry *)ie_buf;
    last_ie->size = sizeof(struct ip_fw_iflist_entry) + sizeof(struct sockaddr_in);
    ie_buf_size = last_ie->size;

    strcpy(last_ie->name, "lo");
    last_ie->unit = last_units[1]++;    // MIB_IF_TYPE_LOOPBACK
    last_ie->indx = 1;         // ??? is it always correct ???
    last_ie->addr_count = 1;

    sin = &last_ie->addr[0];
    memset(sin, 0, sizeof(*sin));
    sin->sin_family = AF_INET;
    sin->sin_addr.s_addr = inet_addr("127.0.0.1");

    printf("%s%d  - MS TCP Loopback (127.0.0.1)\n", last_ie->name, last_ie->unit);

    // next, append information about all another adapters
    n = BUF_SIZE;

    status = GetAdaptersInfo((IP_ADAPTER_INFO *)buf, &n);
    if (status != ERROR_SUCCESS) {
        fprintf(stderr, "GetAdaptersInfo: %d\n", status);

        // ignore error but setup buf to NULL (assume we have only loopback adapter)
        free(buf);
        buf = NULL;
    }

    for (ai = (IP_ADAPTER_INFO *)buf; ai != NULL; ai = ai->Next) {

        ie_buf = (char *)realloc(ie_buf, ie_buf_size + sizeof(struct ip_fw_iflist_entry));
        if (ie_buf == NULL) {
            perror("realloc");
            goto done;
        }

        last_ie = (struct ip_fw_iflist_entry *)(ie_buf + ie_buf_size);
        ie_buf_size += sizeof(struct ip_fw_iflist_entry);
        last_ie->size = sizeof(struct ip_fw_iflist_entry);

        // find adapter name by type
        for (i = 0; i < sizeof(g_if_types) / sizeof(*g_if_types); i++)
            if (g_if_types[i].type == ai->Type)
                break;

        if (i >= sizeof(g_if_types) / sizeof(*g_if_types))
            i = 0;      // MIB_IF_TYPE_OTHER by default

        strcpy(last_ie->name, g_if_types[i].name);

        ifnam = malloc(256);
        if (ifnam == NULL) {
            perror("malloc");
            goto done;
        }
        memset(ifnam, 0, 256);
        if (ai->Type != MIB_IF_TYPE_PPP) {
            last_ie->unit = idx_byguid(ai->AdapterName, ifnam);
            CharToOem(ifnam,ifnam);
            if (last_ie->unit < 1)
                last_ie->unit = last_units[i]++;
        }
        else
            last_ie->unit = last_units[i]++;
        if (strlen(ifnam) < 2)
            strcpy(ifnam, ai->Description);
        if (strlen(ifnam) > 40)
            strncpy(ifnam+37, "...\0", 4);
        last_ie->indx = ai->Index;
        last_ie->addr_count = 0;

        printf("%s%d - %s ", last_ie->name, last_ie->unit, ifnam);
        free(ifnam);

        for (as = &ai->IpAddressList; as != NULL; as = as->Next) {

            if (strcmp(as->IpAddress.String, "0.0.0.0") == 0) {
                ;
                continue;       // not interested in such addresses
            }

            ie_buf_size += sizeof(struct sockaddr_in);
            last_ie->size += sizeof(struct sockaddr_in);

            last_ie_offset = (char *)last_ie - ie_buf;

            ie_buf = (char *)realloc(ie_buf, ie_buf_size);
            if (ie_buf == NULL) {
                perror("realloc");
                goto done;
            }

            // recalc last_ie after realloc()
            last_ie = (struct ip_fw_iflist_entry *)(ie_buf + last_ie_offset);

            sin = &last_ie->addr[last_ie->addr_count++];

            memset(sin, 0, sizeof(*sin));

            sin->sin_family = AF_INET;
            sin->sin_addr.s_addr = inet_addr(as->IpAddress.String);

            printf("(%s)", as->IpAddress.String);
        }
        printf("\n");
    }

    // append the last entry with size = 0

    ie_buf = (char *)realloc(ie_buf, ie_buf_size + sizeof(struct ip_fw_iflist_entry));
    if (ie_buf == NULL) {
        perror("realloc");
        goto done;
    }

    last_ie = (struct ip_fw_iflist_entry *)(ie_buf + ie_buf_size);
    ie_buf_size += sizeof(struct ip_fw_iflist_entry);
    last_ie->size = 0;

    if (cfile == FALSE)
        goto done;

    // ie_buf is ready to be sent!

    device = CreateFile("\\\\.\\Global\\ip_fw", GENERIC_READ | GENERIC_WRITE, \
                        FILE_SHARE_READ | FILE_SHARE_WRITE, \
                        NULL, OPEN_EXISTING, 0, NULL);
    if (device == INVALID_HANDLE_VALUE) {
        void *buf;

        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
                      FORMAT_MESSAGE_FROM_SYSTEM |
                      FORMAT_MESSAGE_IGNORE_INSERTS,
                      NULL,GetLastError(), 0, (LPTSTR) &buf, 0, NULL);
        CharToOem(buf,buf);
        fprintf(stderr, "CreateFile: %s\n", (LPTSTR)buf);
        goto done;
    }
    if (!DeviceIoControl(device, IP_FW_SET_IFLIST, ie_buf, ie_buf_size, NULL, 0, &n, NULL))
        fprintf(stderr, "DeviceIoControl: %d\n", GetLastError());

done:

    if (device != INVALID_HANDLE_VALUE)
        CloseHandle(device);

    if (ie_buf != NULL)
        free(ie_buf);
    if (buf != NULL)
        free(buf);
    if (cfile == TRUE)
        LeaveCriticalSection(&cs);

    return 0;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?