Назад | Перейти на главную страницу

hostapd Проводной 802.1x с мостом

У меня APU PCEngines под управлением Debian Jessie.

Я пытаюсь настроить hostapd для выполнения проводной проверки подлинности 802.1x на удаленном контроллере домена, на котором запущен NPS на 2008 R2.

Я хотел бы, чтобы 2 из его сетевых портов присоединились к интерфейсу моста после аутентификации, в котором будет настроена наша подсеть, запущено DHCP-реле и IP-адрес маршрутизатора, с которым могут разговаривать наши клиенты.

После некоторого покопания параметр конфигурации «мост» в hostapd кажется применимым только для определенных драйверов WiFi, а не для проводного драйвера.

Если я добавляю порты к мосту при загрузке, но на каждом интерфейсе запущен hostapd, пользователи могут передавать трафик и использовать интерфейсы без аутентификации.

Без этого клиенты могут подключаться и аутентифицироваться должным образом, но, очевидно, у них нет сети, с которой они могли бы разговаривать (я пытался настроить параметр конфигурации моста, надеясь, что он автоматически подключится к мосту, но это не так).

Моя конфигурация hostapd выглядит следующим образом:

interface=eth1

driver=wired

ieee8021x=1

use_pae_group_addr=1

eap_reauth_period=3600
eapol_version=2

# RADIUS authentication server
auth_server_addr=**secret**
auth_server_port=1812
auth_server_shared_secret=**secret**
# RADIUS accounting server
acct_server_addr=**secret**
acct_server_port=1813
acct_server_shared_secret=**secret**

logger_syslog=-1
logger_syslog_level=2

Кто-нибудь знает, возможно ли то, что мне нужно, или что я делаю не так?

Редактировать:

Я читал, что hostapd не реализует полный стек аутентификатора для «проводного» драйвера, поэтому его нельзя использовать для защиты порта с помощью 802.1x из коробки.

Я также читал, что можно использовать интерфейс управления для прослушивания событий, а затем использовать внешнюю программу для управления мостом.

Я сделал это, и это работает изначально, но примерно через 3 минуты клиенты всегда отключаются. Он регистрируется в системном журнале из-за бездействия.

Тем не менее, я включу свой CGo-код ниже:

package main

/*
#cgo CFLAGS: -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "libbridge.h"
#include "wpa_ctrl.h"
*/
import "C"
import "unsafe"
import "fmt"
import "time"
import "strings"

var briface string = "br0"
var auiface string = "eth1"
var hostapd_path string = "/var/run/hostapd/"

var connected bool
var current_mac string

var wpa_ctl *C.struct_wpa_ctrl

func main() {
    br_del()

    hostapd_connect()
    defer func(){
        if wpa_ctl != nil {
            C.wpa_ctrl_detach(wpa_ctl)
            C.wpa_ctrl_close(wpa_ctl)
        }
    }()

    for {
        for C.wpa_ctrl_pending(wpa_ctl) > 0 {
            log(fmt.Sprintf("Reading message from hostapd..."))
            var buf [256]C.char
            var llen C.size_t = C.size_t(unsafe.Sizeof(buf) - 1)
            if C.wpa_ctrl_recv(wpa_ctl, &buf[0], &llen) == 0 {
                null := C.CString("\000")
                buf[llen] = *null
                C.free(unsafe.Pointer(null))
                //fmt.Printf("%s\n", C.GoString(&buf[0]))
                msg := C.GoString(&buf[0])
                mData := strings.Split(msg, " ")

                if len(mData) < 2 {
                    log(fmt.Sprintf("Event data too short when processing message: %s", msg))
                    continue
                }
                switch (mData[0]){
                    case "<3>AP-STA-CONNECTED":
                        log(fmt.Sprintf("Got Device Authentication, adding to bridge..."))
                        br_add()
                        connected = true
                        current_mac = mData[1]
                    case "<3>AP-STA-DISCONNECTED":
                        log(fmt.Sprintf("Got Device Disconnect, removing from bridge..."))
                        br_del()
                        connected = false
                    case "<3>CTRL-EVENT-EAP-STARTED":
                        if connected {
                            if mData[1] != current_mac {
                                log(fmt.Sprintf("Got active MAC different from current MAC. %s vs %s - Disconnecting current.", mData[1], current_mac))
                                hostapd_disconnect(current_mac)
                            }
                        }
                }

            } else {
                break
            }
        }

        if ! hostapd_ping() {
            C.wpa_ctrl_detach(wpa_ctl)
            C.wpa_ctrl_close(wpa_ctl)
            log(fmt.Sprintf("Lost connection to hostapd, reconnecting..."))
            hostapd_connect()
        }

        time.Sleep(time.Millisecond * 100)
    }
}

func hostapd_connect(){
    ci := C.CString(hostapd_path + auiface)
    defer C.free(unsafe.Pointer(ci))

    for {
        wpa_ctl = C.wpa_ctrl_open(ci)
        if wpa_ctl != nil {
            log(fmt.Sprintf("Connected to hostapd OK, attach..."))
            if C.wpa_ctrl_attach(wpa_ctl) == 0 {
                log(fmt.Sprintf("Attached event listener..."))
                break
            } else {
                fmt.Printf("Failed to attach to event listener.")
                C.wpa_ctrl_close(wpa_ctl)
            }
        } else {
            log(fmt.Sprintf("Failed to connect to hostapd control socket, waiting for retry..."))
        }
        time.Sleep(time.Millisecond * 100)
    }
}

func hostapd_disconnect(mac string){
    ci := C.CString(hostapd_path + auiface)
    defer C.free(unsafe.Pointer(ci))

    dc := C.wpa_ctrl_open(ci)
    if dc == nil {
        log(fmt.Sprintf("Error opening connection to disconnect current station."))
        return
    }
    defer C.wpa_ctrl_close(dc)

    var buf [4096]C.char
    var len C.size_t = C.size_t(unsafe.Sizeof(buf) - 1)

    cping := C.CString("deauthenticate " + mac)
    defer C.free(unsafe.Pointer(cping))

    ret := C.wpa_ctrl_request(dc, cping, C.strlen(cping), &buf[0], &len, nil)

    if (ret == -2) {
        log(fmt.Sprintf("Station disconnect failed with timeout..."))
    } else if (ret < 0) {
        log(fmt.Sprintf("Station disconnect failed..."))
    }
    log(fmt.Sprintf("Station disconnect requested."))
}

func hostapd_ping() (bool) {
    var buf [4096]C.char
    var len C.size_t = C.size_t(unsafe.Sizeof(buf) - 1)

    cping := C.CString("PING")
    defer C.free(unsafe.Pointer(cping))

    ret := C.wpa_ctrl_request(wpa_ctl, cping, C.strlen(cping), &buf[0], &len, nil)

    if (ret == -2) {
        log(fmt.Sprintf("PING failed with timeout..."))
        return false
    } else if (ret < 0) {
        log(fmt.Sprintf("PING failed..."))
        return false
    }
    return true
}

func br_add(){
    br := C.CString(briface)
    defer C.free(unsafe.Pointer(br))
    ifa := C.CString(auiface)
    defer C.free(unsafe.Pointer(ifa))

    if ( C.br_init() > 0 ) {
        log(fmt.Sprintf("Can't setup bridge control in br_add. Failed to add interface to bridge."))
        return
    }

    ret := C.br_add_interface(br, ifa)
    if ret > 0 {
        log(fmt.Sprintf("Failed to add interface to bridge, error code: %d", ret))
        return
    }
}

func br_del(){
    br := C.CString(briface)
    defer C.free(unsafe.Pointer(br))
    ifa := C.CString(auiface)
    defer C.free(unsafe.Pointer(ifa))

    if ( C.br_init() > 0 ) {
        log(fmt.Sprintf("Can't setup bridge control in br_del. Failed to remove interface from bridge."))
        return
    }

    ret := C.br_del_interface(br, ifa)
    if ret > 0 {
        log(fmt.Sprintf("Failed to remove interface from bridge, error code: %d", ret))
        return
    }
}

func log(data string) {
    fmt.Printf("%s\n", data)
}