diff options
Diffstat (limited to 'src/plugins')
| -rw-r--r-- | src/plugins/ifw/black_list.c | 76 | ||||
| -rw-r--r-- | src/plugins/ifw/black_list.h | 20 | ||||
| -rw-r--r-- | src/plugins/ifw/ifw.h | 48 | ||||
| -rw-r--r-- | src/plugins/ifw/ifw_dbus.c | 456 | ||||
| -rw-r--r-- | src/plugins/ifw/ifw_dbus.h | 43 | ||||
| -rw-r--r-- | src/plugins/ifw/ipset.c | 89 | ||||
| -rw-r--r-- | src/plugins/ifw/ipset.h | 22 | ||||
| -rw-r--r-- | src/plugins/ifw/libnl_ifw.c | 62 | ||||
| -rw-r--r-- | src/plugins/ifw/libnl_ifw.h | 35 | ||||
| -rw-r--r-- | src/plugins/ifw/list.h | 155 | ||||
| -rw-r--r-- | src/plugins/ifw/plugin.c | 224 | ||||
| -rw-r--r-- | src/plugins/ifw/report_list.c | 81 | ||||
| -rw-r--r-- | src/plugins/ifw/report_list.h | 24 | ||||
| -rw-r--r-- | src/plugins/ifw/white_list.c | 119 | ||||
| -rw-r--r-- | src/plugins/ifw/white_list.h | 23 | ||||
| -rw-r--r-- | src/plugins/wireless/plugin.c | 148 | ||||
| -rw-r--r-- | src/plugins/wireless/wpa_ctrl.c | 238 | ||||
| -rw-r--r-- | src/plugins/wireless/wpa_ctrl.h | 179 | 
18 files changed, 2042 insertions, 0 deletions
diff --git a/src/plugins/ifw/black_list.c b/src/plugins/ifw/black_list.c new file mode 100644 index 0000000..1e7dbbb --- /dev/null +++ b/src/plugins/ifw/black_list.c @@ -0,0 +1,76 @@ +#include "black_list.h" +#include "ipset.h" + +#include <stdio.h> +#include <stdlib.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/socket.h> + +void black_list_init(black_list_t *list) { +    INIT_LIST_HEAD(list); +} + +void black_list_add(black_list_t *list, msg_usr_t *attack) { +    black_list_cell_t *cell; + +    cell = malloc(sizeof(black_list_cell_t)); +    if (!cell) { +        fprintf(stderr, "unable to alloc enough memory for black list cell, skipping\n"); +        return; +    } +    cell->info = *attack; +    INIT_LIST_HEAD(&cell->list); +    list_add_tail(&cell->list, list); + +    ipset_blacklist_add(cell->info.s_addr); +} + +black_list_cell_t *black_list_find(black_list_t *list, u_int32_t addr) { +    struct list_head *entry; + +    __list_for_each(entry, list) { +        black_list_cell_t *cell; +        cell = list_entry(entry, black_list_cell_t, list); +        if (cell->info.s_addr == addr) { +            return cell; +        } +    } + +    return NULL; +} + +void black_list_remove(black_list_t *list, u_int32_t addr) { +    black_list_cell_t *cell, *n, *prev; + +    ipset_blacklist_remove(addr); + +    prev = NULL; +    list_for_each_entry_safe(cell, n, list, list) { +        if (prev) +            free(prev); +        if (cell->info.s_addr == addr) { +            list_del(&cell->list); +            prev = cell; +        } else { +            prev = NULL; +        } +    } +    if (prev) +        free(prev); +} + + +void black_list_print(black_list_t *list) { +    struct list_head *entry; + +    printf("* black list {\n"); +    __list_for_each(entry, list) { +        black_list_cell_t *cell; +        struct in_addr addr; +        cell = list_entry(entry, black_list_cell_t, list); +        addr.s_addr = cell->info.s_addr; +        printf("%s,\n", inet_ntoa(addr)); +    } +    printf("} black list *\n"); +} diff --git a/src/plugins/ifw/black_list.h b/src/plugins/ifw/black_list.h new file mode 100644 index 0000000..4cfe74b --- /dev/null +++ b/src/plugins/ifw/black_list.h @@ -0,0 +1,20 @@ +#ifndef BLACK_LIST_H +#define BLACK_LIST_H + +#include "list.h" +typedef struct list_head black_list_t; + +#include "ifw.h" + +typedef struct { +    struct list_head list; +    msg_usr_t info; +}  black_list_cell_t; + +void black_list_init(black_list_t *list); +void black_list_add(black_list_t *list, msg_usr_t *attack); +black_list_cell_t *black_list_find(black_list_t *list, u_int32_t addr); +void black_list_remove(black_list_t *list, u_int32_t addr); +void black_list_print(black_list_t *list); + +#endif /* BLACK_LIST_H */ diff --git a/src/plugins/ifw/ifw.h b/src/plugins/ifw/ifw.h new file mode 100644 index 0000000..f007b0f --- /dev/null +++ b/src/plugins/ifw/ifw.h @@ -0,0 +1,48 @@ +#ifndef IFW_H +#define IFW_H + +#include "plugin.h" + +#define IFW_DBUS_PATH      PLUGIN_ROOT_PATH "/ifw" +#define IFW_DBUS_INTERFACE PLUGIN_ROOT_INTF ".ifw" + +#include <sys/types.h> +#include "libnl_ifw.h" + +#define IFW_SYSCONF_ROOT       "/etc/ifw/" +#define IFW_BLACKLIST_FILENAME IFW_SYSCONF_ROOT "blacklist" +#define IFW_WHITELIST_FILENAME IFW_SYSCONF_ROOT "whitelist" + +typedef enum { +    IFW_MODE_AUTO, +    IFW_MODE_INTERACTIVE +} ifw_mode_t; + +typedef struct { +    long timestamp_sec;             /* date */ +    char indev_name[IFNAMSIZ];      /* input interface */ +    char prefix[PREFSIZ];           /* summary of attack */ +    int sensor;                     /* sensor the alert come from */ +    int protocol;                   /* Protocol */ +    u_int32_t s_addr;               /* source address */ +    u_int16_t d_port;               /* destination port UDP/TCP */ +    u_int8_t icmp_type;             /* icmp type */ +} msg_usr_t; + +typedef struct popup_verdict { +    int seq; +    int bl; +} popup_verdict_t; + +#include "black_list.h" +#include "white_list.h" +#include "report_list.h" + +typedef struct { +    ifw_mode_t mode; +    black_list_t blacklist; +    report_list_t reports; +    white_list_t whitelist;     +} ifw_t; + +#endif /* IFW_H */ diff --git a/src/plugins/ifw/ifw_dbus.c b/src/plugins/ifw/ifw_dbus.c new file mode 100644 index 0000000..82b2675 --- /dev/null +++ b/src/plugins/ifw/ifw_dbus.c @@ -0,0 +1,456 @@ +#include <stdio.h> + +#include "ifw_dbus.h" + +static void ifw_dbus_notify_simple_signal(DBusConnection *bus, char *signal) { +    DBusMessage *message; + +    message = dbus_message_new_signal(IFW_DBUS_PATH, +                                      IFW_DBUS_INTERFACE, +                                      signal); +    dbus_connection_send(bus, message, NULL); +    dbus_connection_flush(bus); +    dbus_message_unref(message); +} + +void ifw_dbus_apply_report_verdict(DBusConnection *connection, ifw_t *ifw, report_list_cell_t *report, int do_blacklist) { +    if (do_blacklist) { +        if (!black_list_find(&ifw->blacklist, report->info.s_addr)) { +            printf("blacklisting seq %d\n", report->seq); +            black_list_add(&ifw->blacklist, &report->info); +            ifw_dbus_notify_blacklist(connection, &report->info); +        } else { +            printf("(seq %d) addr %u already in blacklist\n", report->seq, report->info.s_addr); +        } +    } else { +        printf("ignoring seq %d\n", report->seq); +    } +    report->processed = 1; +} + +/* notify frontends of a new attack with a DBus signal */ +void ifw_dbus_notify_attack(DBusConnection *bus, report_list_cell_t *report) { +    DBusMessage *message; + +    message = dbus_message_new_signal(IFW_DBUS_PATH, +                                      IFW_DBUS_INTERFACE, +                                      "Attack"); + +    dbus_message_append_args(message, +                             DBUS_TYPE_UINT32, +                             report->info.timestamp_sec, +                             DBUS_TYPE_STRING, +                             report->info.indev_name, +                             DBUS_TYPE_STRING, +                             report->info.prefix, +                             DBUS_TYPE_UINT32, +                             report->info.sensor, +                             DBUS_TYPE_UINT32, +                             report->info.protocol, +                             DBUS_TYPE_UINT32, +                             report->info.s_addr, +                             DBUS_TYPE_UINT32, +                             report->info.d_port, +                             DBUS_TYPE_UINT32, +                             report->info.icmp_type, +                             DBUS_TYPE_UINT32, +                             report->seq, +                             DBUS_TYPE_UINT32, +                             report->processed, +                             DBUS_TYPE_INVALID); +    dbus_connection_send(bus, message, NULL); +    dbus_connection_flush(bus); +    dbus_message_unref(message); +} + +/* notify frontends of a new blacklist with a DBus signal */ +void ifw_dbus_notify_blacklist(DBusConnection *bus, msg_usr_t *attack) { +    DBusMessage *message; + +    message = dbus_message_new_signal(IFW_DBUS_PATH, +                                      IFW_DBUS_INTERFACE, +                                      "Blacklist"); + +    dbus_message_append_args(message, +                             DBUS_TYPE_UINT32, +                             attack->timestamp_sec, +                             DBUS_TYPE_STRING, +                             attack->indev_name, +                             DBUS_TYPE_STRING, +                             attack->prefix, +                             DBUS_TYPE_UINT32, +                             attack->sensor, +                             DBUS_TYPE_UINT32, +                             attack->protocol, +                             DBUS_TYPE_UINT32, +                             attack->s_addr, +                             DBUS_TYPE_UINT32, +                             attack->d_port, +                             DBUS_TYPE_UINT32, +                             attack->icmp_type, +                             DBUS_TYPE_INVALID); +    dbus_connection_send(bus, message, NULL); +    dbus_connection_flush(bus); +    dbus_message_unref(message); +} + +/* notify frontends of a new whitelist with a DBus signal */ +void ifw_dbus_notify_whitelist(DBusConnection *bus, u_int32_t addr) { +    DBusMessage *message; + +    message = dbus_message_new_signal(IFW_DBUS_PATH, +                                      IFW_DBUS_INTERFACE, +                                      "Whitelist"); +    dbus_message_append_args(message, +                             DBUS_TYPE_UINT32, +                             addr, +                             DBUS_TYPE_INVALID); +    dbus_connection_send(bus, message, NULL); +    dbus_connection_flush(bus); +    dbus_message_unref(message); +} + +/* notify frontends that ifw data isn't usable with a DBus signal */ +void ifw_dbus_notify_clear(DBusConnection *bus) { +    ifw_dbus_notify_simple_signal(bus, "Clear"); +} + +/* notify frontends that ifw has just been started */ +void ifw_dbus_notify_init(DBusConnection *bus) { +    ifw_dbus_notify_simple_signal(bus, "Init"); +} + +/* notify frontends that a user is aware of the attacks */  +void ifw_dbus_notify_alert_ack(DBusConnection *bus) { +    ifw_dbus_notify_simple_signal(bus, "AlertAck"); +} + +/* notify frontends that a user is wants to review the attacks */  +void ifw_dbus_notify_manage_request(DBusConnection *bus) { +    ifw_dbus_notify_simple_signal(bus, "ManageRequest"); +} + +DBusHandlerResult ifw_dbus_get_mode(DBusConnection *connection, DBusMessage *message, ifw_t *ifw) { +    DBusMessage *reply; + +    reply = dbus_message_new_method_return(message); +    dbus_message_append_args(reply, +                             DBUS_TYPE_UINT32, +                             ifw->mode, +                             DBUS_TYPE_INVALID); +    dbus_connection_send(connection, reply, NULL); +    dbus_connection_flush(connection); +    dbus_message_unref(reply); + +    return DBUS_HANDLER_RESULT_HANDLED; +} + +DBusHandlerResult ifw_dbus_set_mode(DBusConnection *connection, DBusMessage *message, ifw_t *ifw) { +    DBusError error; +    DBusMessage *reply; +    ifw_mode_t mode; + +    dbus_error_init (&error); +    if (!dbus_message_get_args (message, +                                &error, +                                DBUS_TYPE_UINT32, +                                &mode, +                                DBUS_TYPE_INVALID)) { +        fprintf(stderr, "ifw_dbus_set_mode(): failed to read D-BUS message args: %s\n", error.message); +        dbus_error_free (&error); +        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +    } +    dbus_error_free (&error); + +    printf("setting new ifw mode : %s\n", mode == IFW_MODE_AUTO ? "auto" : mode == IFW_MODE_INTERACTIVE ? "interactive" : "unknown"); +    ifw->mode = mode; + +    reply = dbus_message_new_method_return(message); +    dbus_message_append_args(reply, +                             DBUS_TYPE_UINT32, +                             ifw->mode, +                             DBUS_TYPE_INVALID); +    dbus_connection_send(connection, reply, NULL); +    dbus_connection_flush(connection); +    dbus_message_unref(reply); + +    return DBUS_HANDLER_RESULT_HANDLED; +} + +DBusHandlerResult ifw_dbus_get_reports(DBusConnection *connection, DBusMessage *message, ifw_t *ifw) { +    DBusError error; +    struct list_head *entry; +    DBusMessage *reply; +    char include_processed; + +    dbus_error_init (&error); +    if (!dbus_message_get_args (message, +                                &error, +                                DBUS_TYPE_UINT32, +                                &include_processed, +                                DBUS_TYPE_INVALID)) { +        fprintf(stderr, "ifw_dbus_get_reports(): failed to read D-BUS message args: %s\n", error.message); +        dbus_error_free (&error); +        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +    } +    dbus_error_free (&error); + +    reply = dbus_message_new_method_return(message); +    __list_for_each(entry, &ifw->reports) { +        report_list_cell_t *cell; +        cell = list_entry(entry, report_list_cell_t, list); +        if (cell->processed && !include_processed) { +            continue; +        } +        dbus_message_append_args(reply, +                                 DBUS_TYPE_UINT32, +                                 cell->info.timestamp_sec, +                                 DBUS_TYPE_STRING, +                                 cell->info.indev_name, +                                 DBUS_TYPE_STRING, +                                 cell->info.prefix, +                                 DBUS_TYPE_UINT32, +                                 cell->info.sensor, +                                 DBUS_TYPE_UINT32, +                                 cell->info.protocol, +                                 DBUS_TYPE_UINT32, +                                 cell->info.s_addr, +                                 DBUS_TYPE_UINT32, +                                 cell->info.d_port, +                                 DBUS_TYPE_UINT32, +                                 cell->info.icmp_type, +                                 DBUS_TYPE_UINT32, +                                 cell->seq, +                                 DBUS_TYPE_UINT32, +                                 cell->processed, +                                 DBUS_TYPE_INVALID); +    } +    dbus_connection_send(connection, reply, NULL); +    dbus_connection_flush(connection); +    dbus_message_unref(reply); + +    return DBUS_HANDLER_RESULT_HANDLED; +} + +DBusHandlerResult ifw_dbus_get_blacklist(DBusConnection *connection, DBusMessage *message, ifw_t *ifw) { +    struct list_head *entry; +    DBusMessage *reply; + +    reply = dbus_message_new_method_return(message); +    __list_for_each(entry, &ifw->blacklist) { +        black_list_cell_t *cell; +        cell = list_entry(entry, black_list_cell_t, list); +        dbus_message_append_args(reply, +                                 DBUS_TYPE_UINT32, +                                 cell->info.timestamp_sec, +                                 DBUS_TYPE_STRING, +                                 cell->info.indev_name, +                                 DBUS_TYPE_STRING, +                                 cell->info.prefix, +                                 DBUS_TYPE_UINT32, +                                 cell->info.sensor, +                                 DBUS_TYPE_UINT32, +                                 cell->info.protocol, +                                 DBUS_TYPE_UINT32, +                                 cell->info.s_addr, +                                 DBUS_TYPE_UINT32, +                                 cell->info.d_port, +                                 DBUS_TYPE_UINT32, +                                 cell->info.icmp_type, +                                 DBUS_TYPE_INVALID); +    } +    dbus_connection_send(connection, reply, NULL); +    dbus_connection_flush(connection); +    dbus_message_unref(reply); + +    return DBUS_HANDLER_RESULT_HANDLED; +} + +DBusHandlerResult ifw_dbus_set_blacklist_verdict(DBusConnection *connection, DBusMessage *message, ifw_t *ifw) { +    DBusError error; +    DBusMessage *reply; +    int seq, do_blacklist; +    report_list_cell_t *report; + +    dbus_error_init (&error); +    if (!dbus_message_get_args (message, +                                &error, +                                DBUS_TYPE_UINT32, +                                &seq, +                                DBUS_TYPE_UINT32, +                                &do_blacklist, +                                DBUS_TYPE_INVALID)) { +        fprintf(stderr, "ifw_dbus_blacklist(): failed to read D-BUS message args: %s\n", error.message); +        dbus_error_free (&error); +        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +    } +    dbus_error_free (&error); + +    report = report_list_find_seq(&ifw->reports, seq); +    if (report) { +        ifw_dbus_apply_report_verdict(connection, ifw, report, do_blacklist); +    } else { +        fprintf(stderr, "unable find sequence number in report list, skipping\n"); +    } + +    black_list_print(&ifw->blacklist); +    report_list_print(&ifw->reports); + +    reply = dbus_message_new_method_return(message); +    dbus_connection_send(connection, reply, NULL); +    dbus_connection_flush(connection); +    dbus_message_unref(reply); + +    return DBUS_HANDLER_RESULT_HANDLED; +} + +DBusHandlerResult ifw_dbus_unblacklist(DBusConnection *connection, DBusMessage *message, ifw_t *ifw) { +    DBusError error; +    DBusMessage *reply; +    u_int32_t addr; + +    dbus_error_init (&error); +    if (!dbus_message_get_args (message, +                                &error, +                                DBUS_TYPE_UINT32, +                                &addr, +                                DBUS_TYPE_INVALID)) { +        fprintf(stderr, "ifw_dbus_blacklist(): failed to read D-BUS message args: %s\n", error.message); +        dbus_error_free (&error); +        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +    } +    dbus_error_free (&error); + +    black_list_remove(&ifw->blacklist, addr); + +    reply = dbus_message_new_method_return(message); +    dbus_connection_send(connection, reply, NULL); +    dbus_connection_flush(connection); +    dbus_message_unref(reply); + +    return DBUS_HANDLER_RESULT_HANDLED; +} + +DBusHandlerResult ifw_dbus_get_whitelist(DBusConnection *connection, DBusMessage *message, ifw_t *ifw) { +    struct list_head *entry; +    DBusMessage *reply; + +    reply = dbus_message_new_method_return(message); +    __list_for_each(entry, &ifw->whitelist) { +        white_list_cell_t *cell; +        cell = list_entry(entry, white_list_cell_t, list); +        dbus_message_append_args(reply, +                                 DBUS_TYPE_UINT32, +                                 cell->addr, +                                 DBUS_TYPE_INVALID); +    } +    dbus_connection_send(connection, reply, NULL); +    dbus_connection_flush(connection); +    dbus_message_unref(reply); + +    return DBUS_HANDLER_RESULT_HANDLED; +} + +DBusHandlerResult ifw_dbus_whitelist(DBusConnection *connection, DBusMessage *message, ifw_t *ifw) { +    DBusError error; +    DBusMessage *reply; +    u_int32_t addr; + +    dbus_error_init (&error); +    if (!dbus_message_get_args (message, +                                &error, +                                DBUS_TYPE_UINT32, +                                &addr, +                                DBUS_TYPE_INVALID)) { +        fprintf(stderr, "ifw_dbus_whitelist(): failed to read D-BUS message args: %s\n", error.message); +        dbus_error_free (&error); +        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +    } +    dbus_error_free (&error); + +    if (!white_list_find(&ifw->whitelist, addr)) { +        printf("whitelisting addr %u\n", addr); +        white_list_add(&ifw->whitelist, addr); +    } else { +        printf("addr %u already in whitelist\n", addr); +    } +    white_list_print(&ifw->whitelist); + +    reply = dbus_message_new_method_return(message); +    dbus_connection_send(connection, reply, NULL); +    dbus_connection_flush(connection); +    dbus_message_unref(reply); + +    ifw_dbus_notify_whitelist(connection, addr); + +    return DBUS_HANDLER_RESULT_HANDLED; +} + +DBusHandlerResult ifw_dbus_unwhitelist(DBusConnection *connection, DBusMessage *message, ifw_t *ifw) { +    DBusError error; +    DBusMessage *reply; +    u_int32_t addr; + +    dbus_error_init (&error); +    if (!dbus_message_get_args (message, +                                &error, +                                DBUS_TYPE_UINT32, +                                &addr, +                                DBUS_TYPE_INVALID)) { +        fprintf(stderr, "ifw_dbus_whitelist(): failed to read D-BUS message args: %s\n", error.message); +        dbus_error_free (&error); +        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +    } +    dbus_error_free (&error); + +    printf("remove addr from whitelist %u\n", addr); +    white_list_remove(&ifw->whitelist, addr); + +    white_list_print(&ifw->whitelist); + +    reply = dbus_message_new_method_return(message); +    dbus_connection_send(connection, reply, NULL); +    dbus_connection_flush(connection); +    dbus_message_unref(reply); + +    return DBUS_HANDLER_RESULT_HANDLED; +} + +DBusHandlerResult ifw_dbus_clear_processed_reports(DBusConnection *connection, DBusMessage *message, ifw_t *ifw) { +    DBusMessage *reply; + +    report_list_clear_processed(&ifw->reports); + +    reply = dbus_message_new_method_return(message); +    dbus_connection_send(connection, reply, NULL); +    dbus_connection_flush(connection); +    dbus_message_unref(reply); + +    return DBUS_HANDLER_RESULT_HANDLED; +} + +DBusHandlerResult ifw_dbus_send_alert_ack(DBusConnection *connection, DBusMessage *message, ifw_t *ifw) { +    DBusMessage *reply; + +    ifw_dbus_notify_alert_ack(connection); + +    reply = dbus_message_new_method_return(message); +    dbus_connection_send(connection, reply, NULL); +    dbus_connection_flush(connection); +    dbus_message_unref(reply); + +    return DBUS_HANDLER_RESULT_HANDLED; +} + +DBusHandlerResult ifw_dbus_send_manage_request(DBusConnection *connection, DBusMessage *message, ifw_t *ifw) { +    DBusMessage *reply; + +    ifw_dbus_notify_manage_request(connection); + +    reply = dbus_message_new_method_return(message); +    dbus_connection_send(connection, reply, NULL); +    dbus_connection_flush(connection); +    dbus_message_unref(reply); + +    return DBUS_HANDLER_RESULT_HANDLED; +} diff --git a/src/plugins/ifw/ifw_dbus.h b/src/plugins/ifw/ifw_dbus.h new file mode 100644 index 0000000..a4385db --- /dev/null +++ b/src/plugins/ifw/ifw_dbus.h @@ -0,0 +1,43 @@ +#ifndef IFW_DBUS_H +#define IFW_DBUS_H + +#include <dbus/dbus.h> +#include "ifw.h" + +void ifw_dbus_apply_report_verdict(DBusConnection *connection, ifw_t *ifw, report_list_cell_t *report, int do_blacklist); + +/* notify frontends of a new attack with a DBus signal */ +void ifw_dbus_notify_attack(DBusConnection *bus, report_list_cell_t *report); + +/* notify frontends of a new whitelist with a DBus signal */ +void ifw_dbus_notify_whitelist(DBusConnection *bus, u_int32_t addr); + +/* notify frontends of a new blacklist with a DBus signal */ +void ifw_dbus_notify_blacklist(DBusConnection *bus, msg_usr_t *attack); + +/* notify frontends that ifw data isn't usable with a DBus signal */ +void ifw_dbus_notify_clear(DBusConnection *bus); + +/* notify frontends that ifw has just been started */ +void ifw_dbus_notify_init(DBusConnection *bus); + +/* notify frontends that a user is aware of the attacks */  +void ifw_dbus_notify_alert_ack(DBusConnection *bus); + +/* notify frontends that a user is wants to review the attacks */  +void ifw_dbus_notify_manage_request(DBusConnection *bus); + +DBusHandlerResult ifw_dbus_get_mode(DBusConnection *connection, DBusMessage *message, ifw_t *ifw); +DBusHandlerResult ifw_dbus_set_mode(DBusConnection *connection, DBusMessage *message, ifw_t *ifw); +DBusHandlerResult ifw_dbus_get_reports(DBusConnection *connection, DBusMessage *message, ifw_t *ifw); +DBusHandlerResult ifw_dbus_get_blacklist(DBusConnection *connection, DBusMessage *message, ifw_t *ifw); +DBusHandlerResult ifw_dbus_set_blacklist_verdict(DBusConnection *connection, DBusMessage *message, ifw_t *ifw); +DBusHandlerResult ifw_dbus_unblacklist(DBusConnection *connection, DBusMessage *message, ifw_t *ifw); +DBusHandlerResult ifw_dbus_get_whitelist(DBusConnection *connection, DBusMessage *message, ifw_t *ifw); +DBusHandlerResult ifw_dbus_whitelist(DBusConnection *connection, DBusMessage *message, ifw_t *ifw); +DBusHandlerResult ifw_dbus_unwhitelist(DBusConnection *connection, DBusMessage *message, ifw_t *ifw); +DBusHandlerResult ifw_dbus_clear_processed_reports(DBusConnection *connection, DBusMessage *message, ifw_t *ifw); +DBusHandlerResult ifw_dbus_send_alert_ack(DBusConnection *connection, DBusMessage *message, ifw_t *ifw); +DBusHandlerResult ifw_dbus_send_manage_request(DBusConnection *connection, DBusMessage *message, ifw_t *ifw); + +#endif /* IFW_DBUS_H */ diff --git a/src/plugins/ifw/ipset.c b/src/plugins/ifw/ipset.c new file mode 100644 index 0000000..74ca06e --- /dev/null +++ b/src/plugins/ifw/ipset.c @@ -0,0 +1,89 @@ +#include "ipset.h" + +#include <stdio.h> +#include <stdlib.h> +#include <netinet/in.h> + +#define CMD_MAX_SIZE 1024 + +#ifdef IPSET_DEBUG +#define DPRINTF(s) printf("%s\n", s) +#else +#define DPRINTF(s) +#endif + +void ipset_init() { +    char cmd[CMD_MAX_SIZE]; +    snprintf(cmd, CMD_MAX_SIZE, IPSET_CMD " -N " IPSET_BLACKLIST_NAME " iptree --timeout " IPSET_BLACKLIST_TIMEOUT); +    DPRINTF(cmd); +    system(cmd); +    snprintf(cmd, CMD_MAX_SIZE, IPSET_CMD " -N " IPSET_WHITELIST_NAME " iptree"); +    DPRINTF(cmd); +    system(cmd); +} + +void ipset_destroy() { +    char cmd[CMD_MAX_SIZE]; +    snprintf(cmd, CMD_MAX_SIZE, IPSET_CMD " -X " IPSET_BLACKLIST_NAME); +    DPRINTF(cmd); +    system(cmd); +    snprintf(cmd, CMD_MAX_SIZE, IPSET_CMD " -X " IPSET_WHITELIST_NAME); +    DPRINTF(cmd); +    system(cmd); +} + +/* void ipset_blacklist_load(char *filename) { */ +/*     char cmd[CMD_MAX_SIZE]; */ +/*     snprintf(cmd, CMD_MAX_SIZE, IPSET_CMD " -R < %s", filename); */ +/*     DPRINTF(cmd); */ +/*     system(cmd); */ +/* } */ + +/* void ipset_blacklist_save(char *filename) { */ +/*     char cmd[CMD_MAX_SIZE]; */ +/*     snprintf(cmd, CMD_MAX_SIZE, IPSET_CMD " -S " IPSET_BLACKLIST_NAME " > %s", filename); */ +/*     DPRINTF(cmd); */ +/*     system(cmd); */ +/* } */ + +/* void ipset_whitelist_load(char *filename) { */ +/*     char cmd[CMD_MAX_SIZE]; */ +/*     snprintf(cmd, CMD_MAX_SIZE, IPSET_CMD " -R < %s", filename); */ +/*     DPRINTF(cmd); */ +/*     system(cmd); */ +/* } */ + +/* void ipset_whitelist_save(char *filename) { */ +/*     char cmd[CMD_MAX_SIZE]; */ +/*     snprintf(cmd, CMD_MAX_SIZE, IPSET_CMD " -S " IPSET_WHITELIST_NAME " > %s", filename); */ +/*     DPRINTF(cmd); */ +/*     system(cmd); */ +/* } */ + +void ipset_blacklist_add(u_int32_t addr) { +    char cmd[CMD_MAX_SIZE]; +    snprintf(cmd, CMD_MAX_SIZE, IPSET_CMD " -A " IPSET_BLACKLIST_NAME " %u", ntohl(addr)); +    DPRINTF(cmd); +    system(cmd); +} + +void ipset_blacklist_remove(u_int32_t addr) { +    char cmd[CMD_MAX_SIZE]; +    snprintf(cmd, CMD_MAX_SIZE, IPSET_CMD " -D " IPSET_BLACKLIST_NAME " %u", ntohl(addr)); +    DPRINTF(cmd); +    system(cmd); +} + +void ipset_whitelist_add(u_int32_t addr) { +    char cmd[CMD_MAX_SIZE]; +    snprintf(cmd, CMD_MAX_SIZE, IPSET_CMD " -A " IPSET_WHITELIST_NAME " %u", ntohl(addr)); +    DPRINTF(cmd); +    system(cmd); +} + +void ipset_whitelist_remove(u_int32_t addr) { +    char cmd[CMD_MAX_SIZE]; +    snprintf(cmd, CMD_MAX_SIZE, IPSET_CMD " -D " IPSET_WHITELIST_NAME " %u", ntohl(addr)); +    DPRINTF(cmd); +    system(cmd); +} diff --git a/src/plugins/ifw/ipset.h b/src/plugins/ifw/ipset.h new file mode 100644 index 0000000..a78395a --- /dev/null +++ b/src/plugins/ifw/ipset.h @@ -0,0 +1,22 @@ +#ifndef IPSET_H +#define IPSET_H + +#define IPSET_CMD "ipset" +#define IPSET_BLACKLIST_NAME "ifw_bl" +#define IPSET_WHITELIST_NAME "ifw_wl" +#define IPSET_BLACKLIST_TIMEOUT "3600" + +#include <sys/types.h> + +void ipset_init(); +void ipset_destroy(); +/* void ipset_blacklist_load(char *filename); */ +/* void ipset_blacklist_save(char *filename); */ +/* void ipset_whitelist_load(char *filename); */ +/* void ipset_whitelist_save(char *filename); */ +void ipset_blacklist_add(u_int32_t addr); +void ipset_blacklist_remove(u_int32_t addr); +void ipset_whitelist_add(u_int32_t addr); +void ipset_whitelist_remove(u_int32_t addr); + +#endif /* IPSET_H */ diff --git a/src/plugins/ifw/libnl_ifw.c b/src/plugins/ifw/libnl_ifw.c new file mode 100644 index 0000000..bb41363 --- /dev/null +++ b/src/plugins/ifw/libnl_ifw.c @@ -0,0 +1,62 @@ +/* nl_create_socket(), nl_bind_socket() and nl_read_msg() + * for Interactive Firewall + * sbellabes@mandriva.com + */ + + +#include <asm/types.h> +#include <sys/socket.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> +#include <stdio.h> + +#include "libnl_ifw.h" + +int nl_ifw_bind_socket(int s) { +	struct sockaddr_nl saddr_nl; +	int res; + +	memset(&saddr_nl, 0, sizeof(struct sockaddr_nl)); +	saddr_nl.nl_family = AF_NETLINK; +	saddr_nl.nl_pid = getpid(); +	saddr_nl.nl_groups = 10; +	 +	res = bind(s, (struct sockaddr *)&saddr_nl, sizeof(saddr_nl)); +	if (res == -1) { +		perror("nl_bind_socket"); +		return -1; +	} +	return 1; +} + +int nl_ifw_create_socket(void) { +	int s; +	 +	s = socket(PF_NETLINK, SOCK_RAW, NETLINK_IFWLOG); +	if (s < 0) { +		perror("nl_create_socket"); +		return -1; +	} + +	if (nl_ifw_bind_socket(s) < 0) { +		close(s); +		fprintf(stderr, "bind failed\n"); +		return -1; +        } + +	return s; +} + +int nl_ifw_read_msg(int s, struct nlmsghdr *nlh, struct nl_msg *msg) { +	char buf[sizeof(struct nlmsghdr) + sizeof(struct nl_msg)]; +        int ret; + +        ret = recv(s, &buf, sizeof(buf), 0); +	if (ret > 0) { +                if (nlh) memcpy(nlh, buf, sizeof(struct nlmsghdr)); +                if (msg) memcpy(msg, NLMSG_DATA(buf), sizeof(struct nl_msg)); +	} + +	return ret; +} diff --git a/src/plugins/ifw/libnl_ifw.h b/src/plugins/ifw/libnl_ifw.h new file mode 100644 index 0000000..896d05c --- /dev/null +++ b/src/plugins/ifw/libnl_ifw.h @@ -0,0 +1,35 @@ +/* + * libnl_ifw.h + */ + +#ifndef   _LIBNL_IFW_H +#define   _LIBNL_IFW_H + +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> +#include <netinet/udp.h> +#include <linux/if.h> +#include <linux/netlink.h> + +#define NETLINK_IFWLOG	19 + +#define PREFSIZ		32 + +struct nl_msg {				/* Netlink kernel to user message */ +	long timestamp_sec;		/* time packet */ +	char indev_name[IFNAMSIZ];	/* name of the ingoing interface */ +	char outdev_name[IFNAMSIZ];	/* name of the outgoing interface */ +	unsigned char prefix[PREFSIZ];	/* logging informations */ +	struct iphdr ip; +	union { +		struct tcphdr th; +		struct udphdr uh; +	} h; +}; + +int nl_ifw_bind_socket(int s); +int nl_ifw_create_socket(void); +int nl_ifw_read_msg(int s, struct nlmsghdr *nlh, struct nl_msg *msg); + +#endif /* !_LIBNL_IFW_H */ diff --git a/src/plugins/ifw/list.h b/src/plugins/ifw/list.h new file mode 100644 index 0000000..1b55f95 --- /dev/null +++ b/src/plugins/ifw/list.h @@ -0,0 +1,155 @@ +#ifndef LIST_H +#define LIST_H + +/* borrowed from kernel header linux/list.h */ + +#define LIST_POISON1  ((void *) 0x00100100) +#define LIST_POISON2  ((void *) 0x00200200) + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { +	struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ +	struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ +	(ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, +			      struct list_head *prev, +			      struct list_head *next) +{ +	next->prev = new; +	new->next = next; +	new->prev = prev; +	prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ +	__list_add(new, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ +	__list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ +	next->prev = prev; +	prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ +	__list_del(entry->prev, entry->next); +	entry->next = LIST_POISON1; +	entry->prev = LIST_POISON2; +} + +/** + * list_entry - get the struct for this entry + * @ptr:	the &struct list_head pointer. + * @type:	the type of the struct this is embedded in. + * @member:	the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ +	container_of(ptr, type, member) + +/** + * __list_for_each	-	iterate over a list + * @pos:	the &struct list_head to use as a loop counter. + * @head:	the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ +	for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos:	the type * to use as a loop counter. + * @n:		another type * to use as temporary storage + * @head:	the head for your list. + * @member:	the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member)			\ +	for (pos = list_entry((head)->next, typeof(*pos), member),	\ +		n = list_entry(pos->member.next, typeof(*pos), member);	\ +	     &pos->member != (head); 					\ +	     pos = n, n = list_entry(n->member.next, typeof(*n), member)) + + +/* borrowed from kernel header linux/kernel.h */ + +/** + * container_of - cast a member of a structure out to the containing structure + * + * @ptr:	the pointer to the member. + * @type:	the type of the container struct this is embedded in. + * @member:	the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({			\ +        const typeof( ((type *)0)->member ) *__mptr = (ptr);	\ +        (type *)( (char *)__mptr - linux_offsetof(type,member) );}) + + +/* borrowed from linux/stdddef.h */ + +#define linux_offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +#endif /* LIST_H */ diff --git a/src/plugins/ifw/plugin.c b/src/plugins/ifw/plugin.c new file mode 100644 index 0000000..0e6ac69 --- /dev/null +++ b/src/plugins/ifw/plugin.c @@ -0,0 +1,224 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/socket.h> + +#include "ifw.h" +#include "ifw_dbus.h" +#include "ipset.h" + +static int init(plugin_t *plugin, DBusConnection *connection); +static void deinit(plugin_t *plugin, DBusConnection *connection); +static void process_attack(plugin_t *plugin, DBusConnection *connection, int seq, msg_usr_t *attack); +static DBusHandlerResult handle_message(DBusConnection *connection, DBusMessage *message, plugin_t *plugin); +#ifdef IFW_FAKE +static int generate_fake_attack(msg_usr_t *attack); +static void handle_fake(plugin_t *plugin, DBusConnection *connection); +#else +static void handle_incoming(plugin_t *plugin, DBusConnection *connection); +#endif + +static int init(plugin_t *plugin, DBusConnection *connection) { +    ifw_t *ifw; + +    ifw = malloc(sizeof(ifw_t)); +    if (!ifw) { +        fprintf(stderr, "unable to malloc ifw\n"); +        return -1; +    } + +    report_list_init(&ifw->reports); +    black_list_init(&ifw->blacklist); +    white_list_init(&ifw->whitelist); +    white_list_load(&ifw->whitelist, IFW_WHITELIST_FILENAME); + +    ifw->mode = IFW_MODE_INTERACTIVE; + +#ifdef IFW_FAKE +    plugin->fd = 0; +#else +    plugin->fd = nl_ifw_create_socket(); +    if (plugin->fd < 0) { +        fprintf(stderr, "unable to init netlink\n"); +	return -1; +    } +#endif + +    ifw_dbus_notify_clear(connection); +    ifw_dbus_notify_init(connection); + +    plugin->priv = (void *) ifw; + +    return 0; +} + +static void deinit(plugin_t *plugin, DBusConnection *connection) { +    ifw_t *ifw = (ifw_t *) plugin->priv; + +    ifw_dbus_notify_clear(connection); +    close(plugin->fd); +} + +#ifdef IFW_FAKE +#include <time.h> + +static int generate_fake_attack(msg_usr_t *attack) { +    static int seq = 0; +    uint32_t addr = 0xC0A86401; + +    time(&attack->timestamp_sec); +    strcpy(attack->indev_name, "ppp0"); +    attack->sensor = 0; +    attack->protocol = 0; +    attack->icmp_type = 0; +    attack->d_port = 0; +    attack->s_addr = htonl(addr); + +    switch(seq%3) { +    case 0: +        strcpy(attack->prefix, "SCAN"); +        break; +    case 1: +        strcpy(attack->prefix, "SERV"); +        attack->d_port = 22; +        break; +    case 2: +        strcpy(attack->prefix, "PASS"); +        break; +    } + +    addr++; +    seq++; + +    return seq; +} + +static void handle_fake(plugin_t *plugin, DBusConnection *connection) { +    msg_usr_t fake_attack; +    int seq; + +    read(0, NULL, 1); + +    seq = generate_fake_attack(&fake_attack); +    printf("seq : %d\n", seq); + +    process_attack(plugin, connection, seq, &fake_attack); +} + +#else + +static void handle_incoming(plugin_t *plugin, DBusConnection *connection) { +    struct nl_msg msg; +    static int seq = 0; +    msg_usr_t attack; + +    if (nl_ifw_read_msg(plugin->fd, NULL, &msg) <= 0) { +        fprintf(stderr, "unable to read packet from netlink\n"); +        return; +    } + +    attack.timestamp_sec = msg.timestamp_sec; +    strncpy(attack.indev_name, msg.indev_name, IFNAMSIZ); +    strncpy(attack.prefix, (char *) msg.prefix, PREFSIZ); +    attack.sensor = 0; +    attack.protocol = msg.ip.protocol; +    attack.s_addr = msg.ip.saddr; +    switch (msg.ip.protocol) { +    case IPPROTO_TCP: +        attack.d_port = msg.h.th.dest; +        break; +    case IPPROTO_UDP: +        attack.d_port = msg.h.uh.dest; +        break; +    default: +        attack.d_port = 0; +        break; +    } +    attack.icmp_type = 0; + +    process_attack(plugin, connection, seq++, &attack); +} + +#endif + +static void process_attack(plugin_t *plugin, DBusConnection *connection, int seq, msg_usr_t *attack) { +    ifw_t *ifw = (ifw_t *) plugin->priv; +    report_list_cell_t *report; + +    if (black_list_find(&ifw->blacklist, attack->s_addr) || +        white_list_find(&ifw->whitelist, attack->s_addr) || +        report_list_find(&ifw->reports, attack->s_addr, 0)) { +        struct in_addr addr; +        addr.s_addr = attack->s_addr; +        fprintf(stderr, "skipping known address: %s\n", inet_ntoa(addr)); +        return; +    } + +    if (!strcmp(attack->indev_name, "lo")) { +        fprintf(stderr, "skipping loopback interface\n"); +        return; +    } + +    report = report_list_add(&ifw->reports, seq, attack); +    if (report) { +        if (ifw->mode == IFW_MODE_AUTO) { +            /* add ip address in ipset blacklist */ +            ifw_dbus_apply_report_verdict(connection, ifw, report, 1); +        } + +        /* notify the attack to frontends */ +        ifw_dbus_notify_attack(connection, report); +    } + +    black_list_print(&ifw->blacklist); +    white_list_print(&ifw->whitelist); +    report_list_print(&ifw->reports); +} + +static DBusHandlerResult handle_message(DBusConnection *connection, DBusMessage *message, plugin_t *plugin) { +    ifw_t *ifw = (ifw_t *) plugin->priv; +    if (dbus_message_is_method_call(message, IFW_DBUS_INTERFACE, "GetMode")) { +        return ifw_dbus_get_mode(connection, message, ifw); +    } else if (dbus_message_is_method_call(message, IFW_DBUS_INTERFACE, "SetMode")) { +        return ifw_dbus_set_mode(connection, message, ifw); +    } else if (dbus_message_is_method_call(message, IFW_DBUS_INTERFACE, "GetReports")) { +        return ifw_dbus_get_reports(connection, message, ifw); +    } else if (dbus_message_is_method_call(message, IFW_DBUS_INTERFACE, "GetBlacklist")) { +        return ifw_dbus_get_blacklist(connection, message, ifw); +    } else if (dbus_message_is_method_call(message, IFW_DBUS_INTERFACE, "SetBlacklistVerdict")) { +        return ifw_dbus_set_blacklist_verdict(connection, message, ifw); +    } else if (dbus_message_is_method_call(message, IFW_DBUS_INTERFACE, "UnBlacklist")) { +       return ifw_dbus_unblacklist(connection, message, ifw); +    } else if (dbus_message_is_method_call(message, IFW_DBUS_INTERFACE, "GetWhitelist")) { +        return ifw_dbus_get_whitelist(connection, message, ifw); +    } else if (dbus_message_is_method_call(message, IFW_DBUS_INTERFACE, "Whitelist")) { +        return ifw_dbus_whitelist(connection, message, ifw); +    } else if (dbus_message_is_method_call(message, IFW_DBUS_INTERFACE, "UnWhitelist")) { +       return ifw_dbus_unwhitelist(connection, message, ifw); +    } else if (dbus_message_is_method_call(message, IFW_DBUS_INTERFACE, "ClearProcessedReports")) { +       return ifw_dbus_clear_processed_reports(connection, message, ifw); +    } else if (dbus_message_is_method_call(message, IFW_DBUS_INTERFACE, "SendAlertAck")) { +       return ifw_dbus_send_alert_ack(connection, message, ifw); +    } else if (dbus_message_is_method_call(message, IFW_DBUS_INTERFACE, "SendManageRequest")) { +       return ifw_dbus_send_manage_request(connection, message, ifw); +    } + +    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +plugin_t ifw_plugin = { +    .name = "Interactive Firewall", +    .path = IFW_DBUS_PATH, +    .init = init, +#ifdef IFW_FAKE +    .handle_incoming = handle_fake, +#else +    .handle_incoming = handle_incoming, +#endif +    .handle_message = handle_message, +    .deinit = deinit, +}; diff --git a/src/plugins/ifw/report_list.c b/src/plugins/ifw/report_list.c new file mode 100644 index 0000000..c21df7e --- /dev/null +++ b/src/plugins/ifw/report_list.c @@ -0,0 +1,81 @@ +#include "report_list.h" + +#include <stdio.h> +#include <stdlib.h> + +void report_list_init(report_list_t *list) { +    INIT_LIST_HEAD(list); +} + +report_list_cell_t *report_list_add(report_list_t *list, int seq, msg_usr_t *attack) { +    report_list_cell_t *cell; + +    cell = malloc(sizeof(report_list_cell_t)); +    if (!cell) { +        fprintf(stderr, "unable to alloc enough memory for report list cell, skipping\n"); +        return NULL; +    } +    cell->seq = seq; +    cell->info = *attack; +    cell->processed = 0; +    INIT_LIST_HEAD(&cell->list); +    list_add_tail(&cell->list, list); + +    return cell; +} + +report_list_cell_t *report_list_find(report_list_t *list, u_int32_t addr, int include_processed) { +    struct list_head *entry; + +    __list_for_each(entry, list) { +        report_list_cell_t *cell; +        cell = list_entry(entry, report_list_cell_t, list); +        if (cell->info.s_addr == addr && include_processed || !cell->processed) { +            return cell; +        } +    } + +    return NULL; +} + +report_list_cell_t *report_list_find_seq(report_list_t *list, int seq) { +    struct list_head *entry; + +    __list_for_each(entry, list) { +        report_list_cell_t *cell; +        cell = list_entry(entry, report_list_cell_t, list); +        if (cell->seq == seq) { +            return cell; +        } +    } + +    return NULL; +} + +void report_list_remove(report_list_cell_t *cell) { +    list_del(&cell->list); +    free(cell); +} + +void report_list_clear_processed(report_list_t *list) { +    report_list_cell_t *cell, *n; + +    list_for_each_entry_safe(cell, n, list, list) { +        if (cell->processed) { +            report_list_remove(cell); +        } +    } +} + +void report_list_print(report_list_t *list) { +    struct list_head *entry; + +    printf("* report list {\n"); +    __list_for_each(entry, list) { +        report_list_cell_t *cell; +        cell = list_entry(entry, report_list_cell_t, list); +        printf("%d,\n", cell->seq); +    } +    printf("} report list *\n"); +} + diff --git a/src/plugins/ifw/report_list.h b/src/plugins/ifw/report_list.h new file mode 100644 index 0000000..626afed --- /dev/null +++ b/src/plugins/ifw/report_list.h @@ -0,0 +1,24 @@ +#ifndef REPORT_LIST_H +#define REPORT_LIST_H + +#include "list.h" +typedef struct list_head report_list_t; + +#include "ifw.h" + +typedef struct { +    struct list_head list; +    int seq; +    msg_usr_t info; +    char processed; +} report_list_cell_t; + +void report_list_init(report_list_t *list); +report_list_cell_t *report_list_add(report_list_t *list, int seq, msg_usr_t *attack); +report_list_cell_t *report_list_find(report_list_t *list, u_int32_t addr, int include_processed); +report_list_cell_t *report_list_find_seq(report_list_t *list, int seq); +void report_list_remove(report_list_cell_t *cell); +void report_list_clear_processed(report_list_t *list); +void report_list_print(report_list_t *list); + +#endif /* REPORT_LIST_H */ diff --git a/src/plugins/ifw/white_list.c b/src/plugins/ifw/white_list.c new file mode 100644 index 0000000..4318abc --- /dev/null +++ b/src/plugins/ifw/white_list.c @@ -0,0 +1,119 @@ +#include "white_list.h" +#include "ipset.h" +#include "ifw.h" + +#include <stdio.h> +#include <stdlib.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/socket.h> + +void white_list_init(white_list_t *list) { +    INIT_LIST_HEAD(list); +} + +void white_list_add(white_list_t *list, u_int32_t addr) { +    white_list_cell_t *cell; + +    cell = malloc(sizeof(white_list_cell_t)); +    if (!cell) { +        fprintf(stderr, "unable to alloc enough memory for white list cell, skipping\n"); +        return; +    } +    cell->addr = addr; +    INIT_LIST_HEAD(&cell->list); +    list_add_tail(&cell->list, list); + +    ipset_whitelist_add(cell->addr); +    white_list_save(list, IFW_WHITELIST_FILENAME); +} + +white_list_cell_t *white_list_find(white_list_t *list, u_int32_t addr) { +    struct list_head *entry; + +    __list_for_each(entry, list) { +        white_list_cell_t *cell; +        cell = list_entry(entry, white_list_cell_t, list); +        if (cell->addr == addr) { +            return cell; +        } +    } + +    return NULL; +} + +void white_list_remove(white_list_t *list, u_int32_t addr) { +    white_list_cell_t *cell, *n, *prev; + +    ipset_whitelist_remove(addr); + +    prev = NULL; +    list_for_each_entry_safe(cell, n, list, list) { +        if (prev) +            free(prev); +        if (cell->addr == addr) { +            list_del(&cell->list); +            prev = cell; +        } else { +            prev = NULL; +        } +    } +    if (prev) +        free(prev); + +    white_list_save(list, IFW_WHITELIST_FILENAME); +} + + +void white_list_print(white_list_t *list) { +    struct list_head *entry; + +    printf("* white list {\n"); +    __list_for_each(entry, list) { +        white_list_cell_t *cell; +        struct in_addr addr; +        cell = list_entry(entry, white_list_cell_t, list); +        addr.s_addr = cell->addr; +        printf("%s,\n", inet_ntoa(addr)); +    } +    printf("} white list *\n"); +} + +void white_list_load(white_list_t *list, const char *filepath) { +    FILE *fp; + +    fp = fopen(filepath, "r"); +    if (fp) { +        char addr_str[16]; +        struct in_addr addr; +        while (fscanf(fp, "%15s\n", addr_str) > 0) { +            if (inet_aton(addr_str, &addr)) { +                white_list_add(list, addr.s_addr); +                printf("adding IP address in white list: %s\n", addr_str); +            } else { +                fprintf(stderr, "unable to parse IP address in white list: %s\n", addr_str); +            } +        } +    } else { +        fprintf(stderr, "unable to open white list file\n"); +    } +} + +void white_list_save(white_list_t *list, const char *filepath) { +    FILE *fp; +    struct list_head *entry; + +    fp = fopen(filepath, "w+"); +    if (fp) { +        __list_for_each(entry, list) { +            white_list_cell_t *cell; +            struct in_addr addr; +            cell = list_entry(entry, white_list_cell_t, list); +            addr.s_addr = cell->addr; +            fprintf(fp, "%15s\n", inet_ntoa(addr)); +            printf("adding IP address in white list: %s\n", inet_ntoa(addr)); +        } +    } else { +        fprintf(stderr, "unable to write white list file\n"); +    } +} diff --git a/src/plugins/ifw/white_list.h b/src/plugins/ifw/white_list.h new file mode 100644 index 0000000..564f5ee --- /dev/null +++ b/src/plugins/ifw/white_list.h @@ -0,0 +1,23 @@ +#ifndef WHITE_LIST_H +#define WHITE_LIST_H + +#include "list.h" + +#include <sys/types.h> + +typedef struct list_head white_list_t; + +typedef struct { +    struct list_head list; +    u_int32_t addr; +}  white_list_cell_t; + +void white_list_init(white_list_t *list); +void white_list_add(white_list_t *list, u_int32_t addr); +white_list_cell_t *white_list_find(white_list_t *list, u_int32_t addr); +void white_list_remove(white_list_t *list, u_int32_t addr); +void white_list_print(white_list_t *list); +void white_list_load(white_list_t *list, const char *filepath); +void white_list_save(white_list_t *list, const char *filepath); + +#endif /* WHITE_LIST_H */ diff --git a/src/plugins/wireless/plugin.c b/src/plugins/wireless/plugin.c new file mode 100644 index 0000000..1ddeb95 --- /dev/null +++ b/src/plugins/wireless/plugin.c @@ -0,0 +1,148 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <dirent.h> + +#include "wpa_ctrl.h" +#include "plugin.h" + +#define WIRELESS_PATH      PLUGIN_ROOT_PATH "/wireless" +#define WIRELESS_INTERFACE PLUGIN_ROOT_INTF ".wireless" + +static int init(plugin_t *plugin, DBusConnection *connection); +static void deinit(plugin_t *plugin, DBusConnection *connection); +static void handle_incoming(plugin_t *plugin, DBusConnection *connection); +static DBusHandlerResult handle_message(DBusConnection *connection, DBusMessage *message, plugin_t *plugin); +static DBusHandlerResult select_network(DBusConnection *connection, DBusMessage *message, plugin_t *plugin); +static DBusHandlerResult wpa_supplicant_request(DBusConnection *connection, DBusMessage *message, plugin_t *plugin, char *cmd); + +static int init(plugin_t *plugin, DBusConnection *connection) { +    struct wpa_ctrl *ctrl_conn = NULL; +    const char *ctrl_iface_dir = "/var/run/wpa_supplicant"; +    DIR *dir = opendir(ctrl_iface_dir); + +    if (dir) { +        struct dirent *dent; +        while ((dent = readdir(dir))) { +            char *cfile; +            int flen; +            if (strcmp(dent->d_name, ".") == 0 || +                strcmp(dent->d_name, "..") == 0) +                continue; +            printf("Selected interface '%s'\n", +                   dent->d_name); +            flen = strlen(ctrl_iface_dir) + strlen(dent->d_name) + 2; +            cfile = malloc(flen); +            if (cfile == NULL) +                return -1; +            snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, dent->d_name); +            ctrl_conn = wpa_ctrl_open(cfile); +            free(cfile); +            break; +        } +        closedir(dir); +    } + +    if (ctrl_conn != NULL) { +        plugin->fd = wpa_ctrl_get_fd(ctrl_conn); +    } else { +        /* do not fail, the plugin will try to re-init when needed */ +        plugin->fd = -1; +    } +    plugin->priv = (void *) ctrl_conn; +    return 0; +} + +static void deinit(plugin_t *plugin, DBusConnection *connection) { +    if (plugin->fd > 0) +        close(plugin->fd); +} + +static void handle_incoming(plugin_t *plugin, DBusConnection *connection) { +    struct wpa_ctrl *ctrl_conn = (struct wpa_ctrl *) plugin->priv; +    char buf[2048]; +    size_t len; +    wpa_ctrl_recv(ctrl_conn, buf, &len); +    buf[len] = '\0'; +    printf("received event: %s\n", buf); +} + +static DBusHandlerResult handle_message(DBusConnection *connection, DBusMessage *message, plugin_t *plugin) { +    if (dbus_message_is_method_call(message, WIRELESS_INTERFACE, "ScanResults")) { +        return wpa_supplicant_request(connection, message, plugin, "SCAN_RESULTS"); +    } else if (dbus_message_is_method_call(message, WIRELESS_INTERFACE, "ListNetworks")) { +        return wpa_supplicant_request(connection, message, plugin, "LIST_NETWORKS"); +    } else if (dbus_message_is_method_call(message, WIRELESS_INTERFACE, "SelectNetwork")) { +        return select_network(connection, message, plugin); +    } +    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static DBusHandlerResult select_network(DBusConnection *connection, DBusMessage *message, plugin_t *plugin) { +    DBusError error; +    u_int32_t net; +    char cmd[32]; + +    dbus_error_init (&error); +    if (!dbus_message_get_args (message, +                                &error, +                                DBUS_TYPE_UINT32, +                                &net, +                                DBUS_TYPE_INVALID)) { +        fprintf(stderr, "select_network(): failed to read D-BUS message args: %s\n", error.message); +        dbus_error_free (&error); +        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +    } +    dbus_error_free (&error); + +    snprintf(cmd, sizeof(cmd), "SELECT_NETWORK %u", net); +    return wpa_supplicant_request(connection, message, plugin, cmd); +} + +static DBusHandlerResult wpa_supplicant_request(DBusConnection *connection, DBusMessage *message, plugin_t *plugin, char *cmd) { +    struct wpa_ctrl *ctrl_conn = (struct wpa_ctrl *) plugin->priv; +    DBusMessage *reply; +    char buf[2048]; +    size_t len; +    int ret = -1; + +    len = sizeof(buf) - 1; +    if (ctrl_conn) { +        ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, &len, NULL); +    } +    if (ret == -1) { +        fprintf(stderr, "connection to wpa_supplicant daemon lost, reconnecting\n"); +        init(plugin, connection); +        ctrl_conn = (struct wpa_ctrl *) plugin->priv; +        if (ctrl_conn) { +            ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, &len, NULL); +        } +    } +    if (ret != 0) { +	fprintf(stderr, "unable to request command\n"); +	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +    } +    buf[len] = '\0'; + +    reply = dbus_message_new_method_return(message); +    dbus_message_append_args(reply, +			     DBUS_TYPE_STRING, +			     buf, +			     DBUS_TYPE_INVALID); +    dbus_connection_send(connection, reply, NULL); +    dbus_connection_flush(connection); +    dbus_message_unref(reply); + +    return DBUS_HANDLER_RESULT_HANDLED; +} + +plugin_t wpa_supplicant_plugin = { +    .name = "Wireless", +    .path = WIRELESS_PATH, +    .init = init, +    .handle_incoming = handle_incoming, +    .handle_message = handle_message, +    .deinit = deinit, +}; diff --git a/src/plugins/wireless/wpa_ctrl.c b/src/plugins/wireless/wpa_ctrl.c new file mode 100644 index 0000000..1c88e69 --- /dev/null +++ b/src/plugins/wireless/wpa_ctrl.c @@ -0,0 +1,238 @@ +/* + * wpa_supplicant/hostapd control interface library + * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/time.h> +#ifndef CONFIG_NATIVE_WINDOWS +#include <sys/socket.h> +#include <sys/un.h> +#endif /* CONFIG_NATIVE_WINDOWS */ + +#include "wpa_ctrl.h" +#ifdef CONFIG_NATIVE_WINDOWS +#include "common.h" +#endif /* CONFIG_NATIVE_WINDOWS */ + + +/** + * struct wpa_ctrl - Internal structure for control interface library + * + * This structure is used by the wpa_supplicant/hostapd control interface + * library to store internal data. Programs using the library should not touch + * this data directly. They can only use the pointer to the data structure as + * an identifier for the control interface connection and use this as one of + * the arguments for most of the control interface library functions. + */ +struct wpa_ctrl { +	int s; +#ifdef CONFIG_CTRL_IFACE_UDP +	struct sockaddr_in local; +	struct sockaddr_in dest; +#else /* CONFIG_CTRL_IFACE_UDP */ +	struct sockaddr_un local; +	struct sockaddr_un dest; +#endif /* CONFIG_CTRL_IFACE_UDP */ +}; + + +struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) +{ +	struct wpa_ctrl *ctrl; +#ifndef CONFIG_CTRL_IFACE_UDP +	static int counter = 0; +#endif /* CONFIG_CTRL_IFACE_UDP */ + +	ctrl = malloc(sizeof(*ctrl)); +	if (ctrl == NULL) +		return NULL; +	memset(ctrl, 0, sizeof(*ctrl)); + +#ifdef CONFIG_CTRL_IFACE_UDP +	ctrl->s = socket(PF_INET, SOCK_DGRAM, 0); +	if (ctrl->s < 0) { +		perror("socket"); +		free(ctrl); +		return NULL; +	} + +	ctrl->local.sin_family = AF_INET; +	ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1); +	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, +		 sizeof(ctrl->local)) < 0) { +		close(ctrl->s); +		free(ctrl); +		return NULL; +	} + +	ctrl->dest.sin_family = AF_INET; +	ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1); +	ctrl->dest.sin_port = htons(9877); +	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, +		    sizeof(ctrl->dest)) < 0) { +		perror("connect"); +		close(ctrl->s); +		free(ctrl); +		return NULL; +	} +#else /* CONFIG_CTRL_IFACE_UDP */ +	ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0); +	if (ctrl->s < 0) { +		free(ctrl); +		return NULL; +	} + +	ctrl->local.sun_family = AF_UNIX; +	snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path), +		 "/tmp/wpa_ctrl_%d-%d", getpid(), counter++); +	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, +		    sizeof(ctrl->local)) < 0) { +		close(ctrl->s); +		free(ctrl); +		return NULL; +	} + +	ctrl->dest.sun_family = AF_UNIX; +	snprintf(ctrl->dest.sun_path, sizeof(ctrl->dest.sun_path), "%s", +		 ctrl_path); +	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, +		    sizeof(ctrl->dest)) < 0) { +		close(ctrl->s); +		unlink(ctrl->local.sun_path); +		free(ctrl); +		return NULL; +	} +#endif /* CONFIG_CTRL_IFACE_UDP */ + +	return ctrl; +} + + +void wpa_ctrl_close(struct wpa_ctrl *ctrl) +{ +#ifndef CONFIG_CTRL_IFACE_UDP +	unlink(ctrl->local.sun_path); +#endif /* CONFIG_CTRL_IFACE_UDP */ +	close(ctrl->s); +	free(ctrl); +} + + +int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, +		     char *reply, size_t *reply_len, +		     void (*msg_cb)(char *msg, size_t len)) +{ +	struct timeval tv; +	int res; +	fd_set rfds; + +	if (send(ctrl->s, cmd, cmd_len, 0) < 0) +		return -1; + +	for (;;) { +		tv.tv_sec = 2; +		tv.tv_usec = 0; +		FD_ZERO(&rfds); +		FD_SET(ctrl->s, &rfds); +		res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv); +		if (FD_ISSET(ctrl->s, &rfds)) { +			res = recv(ctrl->s, reply, *reply_len, 0); +			if (res < 0) +				return res; +			if (res > 0 && reply[0] == '<') { +				/* This is an unsolicited message from +				 * wpa_supplicant, not the reply to the +				 * request. Use msg_cb to report this to the +				 * caller. */ +				if (msg_cb) { +					/* Make sure the message is nul +					 * terminated. */ +					if ((size_t) res == *reply_len) +						res = (*reply_len) - 1; +					reply[res] = '\0'; +					msg_cb(reply, res); +				} +				continue; +			} +			*reply_len = res; +			break; +		} else { +			return -2; +		} +	} +	return 0; +} + + +static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach) +{ +	char buf[10]; +	int ret; +	size_t len = 10; + +	ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6, +			       buf, &len, NULL); +	if (ret < 0) +		return ret; +	if (len == 3 && memcmp(buf, "OK\n", 3) == 0) +		return 0; +	return -1; +} + + +int wpa_ctrl_attach(struct wpa_ctrl *ctrl) +{ +	return wpa_ctrl_attach_helper(ctrl, 1); +} + + +int wpa_ctrl_detach(struct wpa_ctrl *ctrl) +{ +	return wpa_ctrl_attach_helper(ctrl, 0); +} + + +int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) +{ +	int res; + +	res = recv(ctrl->s, reply, *reply_len, 0); +	if (res < 0) +		return res; +	*reply_len = res; +	return 0; +} + + +int wpa_ctrl_pending(struct wpa_ctrl *ctrl) +{ +	struct timeval tv; +	int res; +	fd_set rfds; +	tv.tv_sec = 0; +	tv.tv_usec = 0; +	FD_ZERO(&rfds); +	FD_SET(ctrl->s, &rfds); +	res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv); +	return FD_ISSET(ctrl->s, &rfds); +} + + +int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) +{ +	return ctrl->s; +} diff --git a/src/plugins/wireless/wpa_ctrl.h b/src/plugins/wireless/wpa_ctrl.h new file mode 100644 index 0000000..964f7ab --- /dev/null +++ b/src/plugins/wireless/wpa_ctrl.h @@ -0,0 +1,179 @@ +/* + * wpa_supplicant/hostapd control interface library + * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef WPA_CTRL_H +#define WPA_CTRL_H + +#ifdef  __cplusplus +extern "C" { +#endif + +/* wpa_supplicant control interface - fixed message prefixes */ + +/** Interactive request for identity/password/pin */ +#define WPA_CTRL_REQ "CTRL-REQ-" + +/** Response to identity/password/pin request */ +#define WPA_CTRL_RSP "CTRL-RSP-" + +/* Event messages with fixed prefix */ +/** Authentication completed successfully and data connection enabled */ +#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED " +/** Disconnected, data connection is not available */ +#define WPA_EVENT_DISCONNECTED "CTRL-EVENT-DISCONNECTED " +/** wpa_supplicant is exiting */ +#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING " +/** Password change was completed successfully */ +#define WPA_EVENT_PASSWORD_CHANGED "CTRL-EVENT-PASSWORD-CHANGED " +/** EAP-Request/Notification received */ +#define WPA_EVENT_EAP_NOTIFICATION "CTRL-EVENT-EAP-NOTIFICATION " +/** EAP authentication started (EAP-Request/Identity received) */ +#define WPA_EVENT_EAP_STARTED "CTRL-EVENT-EAP-STARTED " +/** EAP method selected */ +#define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD " +/** EAP authentication completed successfully */ +#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS " +/** EAP authentication failed (EAP-Failure received) */ +#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE " + + +/* wpa_supplicant/hostapd control interface access */ + +/** + * wpa_ctrl_open - Open a control interface to wpa_supplicant/hostapd + * @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used. + * Returns: Pointer to abstract control interface data or %NULL on failure + * + * This function is used to open a control interface to wpa_supplicant/hostapd. + * ctrl_path is usually /var/run/wpa_supplicant or /var/run/hostapd. This path + * is configured in wpa_supplicant/hostapd and other programs using the control + * interface need to use matching path configuration. + */ +struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path); + + +/** + * wpa_ctrl_close - Close a control interface to wpa_supplicant/hostapd + * @ctrl: Control interface data from wpa_ctrl_open() + * + * This function is used to close a control interface. + */ +void wpa_ctrl_close(struct wpa_ctrl *ctrl); + + +/** + * wpa_ctrl_request - Send a command to wpa_supplicant/hostapd + * @ctrl: Control interface data from wpa_ctrl_open() + * @cmd: Command; usually, ASCII text, e.g., "PING" + * @cmd_len: Length of the cmd in bytes + * @reply: Buffer for the response + * @reply_len: Reply buffer length + * @msg_cb: Callback function for unsolicited messages or %NULL if not used + * Returns: 0 on success, -1 on error (send or receive failed), -2 on timeout + * + * This function is used to send commands to wpa_supplicant/hostapd. Received + * response will be written to reply and reply_len is set to the actual length + * of the reply. This function will block for up to two seconds while waiting + * for the reply. If unsolicited messages are received, the blocking time may + * be longer. + * + * msg_cb can be used to register a callback function that will be called for + * unsolicited messages received while waiting for the command response. These + * messages may be received if wpa_ctrl_request() is called at the same time as + * wpa_supplicant/hostapd is sending such a message. This can happen only if + * the program has used wpa_ctrl_attach() to register itself as a monitor for + * event messages. Alternatively to msg_cb, programs can register two control + * interface connections and use one of them for commands and the other one for + * receiving event messages, in other words, call wpa_ctrl_attach() only for + * the control interface connection that will be used for event messages. + */ +int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, +		     char *reply, size_t *reply_len, +		     void (*msg_cb)(char *msg, size_t len)); + + +/** + * wpa_ctrl_attach - Register as an event monitor for the control interface + * @ctrl: Control interface data from wpa_ctrl_open() + * Returns: 0 on success, -1 on failure, -2 on timeout + * + * This function registers the control interface connection as a monitor for + * wpa_supplicant/hostapd events. After a success wpa_ctrl_attach() call, the + * control interface connection starts receiving event messages that can be + * read with wpa_ctrl_recv(). + */ +int wpa_ctrl_attach(struct wpa_ctrl *ctrl); + + +/** + * wpa_ctrl_detach - Unregister event monitor from the control interface + * @ctrl: Control interface data from wpa_ctrl_open() + * Returns: 0 on success, -1 on failure, -2 on timeout + * + * This function unregisters the control interface connection as a monitor for + * wpa_supplicant/hostapd events, i.e., cancels the registration done with + * wpa_ctrl_attach(). + */ +int wpa_ctrl_detach(struct wpa_ctrl *ctrl); + + +/** + * wpa_ctrl_recv - Receive a pending control interface message + * @ctrl: Control interface data from wpa_ctrl_open() + * @reply: Buffer for the message data + * @reply_len: Length of the reply buffer + * Returns: 0 on success, -1 on failure + * + * This function will receive a pending control interface message. This + * function will block if no messages are available. The received response will + * be written to reply and reply_len is set to the actual length of the reply. + * wpa_ctrl_recv() is only used for event messages, i.e., wpa_ctrl_attach() + * must have been used to register the control interface as an event monitor. + */ +int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len); + + +/** + * wpa_ctrl_pending - Check whether there are pending event messages + * @ctrl: Control interface data from wpa_ctrl_open() + * Returns: Non-zero if there are pending messages + * + * This function will check whether there are any pending control interface + * message available to be received with wpa_ctrl_recv(). wpa_ctrl_pending() is + * only used for event messages, i.e., wpa_ctrl_attach() must have been used to + * register the control interface as an event monitor. + */ +int wpa_ctrl_pending(struct wpa_ctrl *ctrl); + + +/** + * wpa_ctrl_get_fd - Get file descriptor used by the control interface + * @ctrl: Control interface data from wpa_ctrl_open() + * Returns: File descriptor used for the connection + * + * This function can be used to get the file descriptor that is used for the + * control interface connection. The returned value can be used, e.g., with + * select() while waiting for multiple events. + * + * The returned file descriptor must not be used directly for sending or + * receiving packets; instead, the library functions wpa_ctrl_request() and + * wpa_ctrl_recv() must be used for this. + */ +int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl); + +#ifdef  __cplusplus +} +#endif + +#endif /* WPA_CTRL_H */  | 
