#include "Lorcon.h" #include "ruby.h" /* self.license = GPLv2; */ /* This is a derivative of the tx.c sample included with lorcon: http://802.11ninja.net/lorcon/ lorcon is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. lorcon is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with lorcon; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Copyright (c) 2005 dragorn and Joshua Wright */ /* Lots of code borrowed from Tom Wambold's pylorcon: http://pylorcon.googlecode.com/ - tom5760[at]gmail.com */ /* All ruby-lorcon/rubyisms are by Rapid7 LLC (C) 2006-2007 http://metasploit.com/ - msfdev[at]metasploit.com */ VALUE mLorcon; VALUE cDevice; VALUE lorcon_get_version(VALUE self) { return INT2NUM(tx80211_getversion()); } VALUE lorcon_cap_to_list(int cap) { VALUE list; list = rb_ary_new(); if ((cap & TX80211_CAP_SNIFF) != 0) rb_ary_push(list, rb_str_new2("SNIFF")); if ((cap & TX80211_CAP_TRANSMIT) != 0) rb_ary_push(list, rb_str_new2("TRANSMIT")); if ((cap & TX80211_CAP_SEQ) != 0) rb_ary_push(list, rb_str_new2("SEQ")); if ((cap & TX80211_CAP_BSSTIME) != 0) rb_ary_push(list, rb_str_new2("BSSTIME")); if ((cap & TX80211_CAP_FRAG) != 0) rb_ary_push(list, rb_str_new2("FRAG")); if ((cap & TX80211_CAP_CTRL) != 0) rb_ary_push(list, rb_str_new2("CTRL")); if ((cap & TX80211_CAP_DURID) != 0) rb_ary_push(list, rb_str_new2("DURID")); if ((cap & TX80211_CAP_SNIFFACK) != 0) rb_ary_push(list, rb_str_new2("SNIFFACK")); if ((cap & TX80211_CAP_SELFACK) != 0) rb_ary_push(list, rb_str_new2("SELFACK")); if ((cap & TX80211_CAP_TXNOWAIT) != 0) rb_ary_push(list, rb_str_new2("TXNOWAIT")); if ((cap & TX80211_CAP_DSSSTX) != 0) rb_ary_push(list, rb_str_new2("DSSSTX")); if ((cap & TX80211_CAP_OFDMTX) != 0) rb_ary_push(list, rb_str_new2("OFDMTX")); if ((cap & TX80211_CAP_MIMOTX) != 0) rb_ary_push(list, rb_str_new2("MIMOTX")); if ((cap & TX80211_CAP_SETRATE) != 0) rb_ary_push(list, rb_str_new2("SETRATE")); if ((cap & TX80211_CAP_SETMODULATION) != 0) rb_ary_push(list, rb_str_new2("SETMODULATION")); if ((cap & TX80211_CAP_NONE) != 0) rb_ary_push(list, rb_str_new2("NONE")); return list; } static VALUE lorcon_driver_list(VALUE self) { VALUE list; VALUE hash; struct tx80211_cardlist *cards = NULL; int i; list = rb_hash_new(); cards = tx80211_getcardlist(); if (cards == NULL) { return(Qnil); } for (i = 1; i < cards->num_cards; i++) { hash = rb_hash_new(); rb_hash_aset(hash, rb_str_new2("name"), rb_str_new2(cards->cardnames[i])); rb_hash_aset(hash, rb_str_new2("description"), rb_str_new2(cards->descriptions[i])); rb_hash_aset(hash, rb_str_new2("capabilities"), lorcon_cap_to_list(cards->capabilities[i])); rb_hash_aset(list, rb_str_new2(cards->cardnames[i]), hash); } tx80211_freecardlist(cards); return(list); } static VALUE lorcon_device_get_channel(VALUE self) { struct rldev *rld; Data_Get_Struct(self, struct rldev, rld); return INT2NUM(tx80211_getchannel(&rld->in_tx)); } static VALUE lorcon_device_set_channel(VALUE self, VALUE channel) { struct rldev *rld; Data_Get_Struct(self, struct rldev, rld); tx80211_setchannel(&rld->in_tx, NUM2INT(channel)); return INT2NUM(tx80211_getchannel(&rld->in_tx)); } void lorcon_device_free(struct rldev *rld) { if (tx80211_getmode(&rld->in_tx) >= 0) { tx80211_close(&rld->in_tx); } free(&rld->in_tx); } static VALUE lorcon_device_get_mode(VALUE self) { struct rldev *rld; int mode; Data_Get_Struct(self, struct rldev, rld); mode = tx80211_getmode(&rld->in_tx); if (mode < 0) { rb_raise(rb_eArgError, "Lorcon could not determine the mode of this device: %s", tx80211_geterrstr(&rld->in_tx)); return(Qnil); } switch (mode) { case TX80211_MODE_AUTO: return rb_str_new2("AUTO"); break; case TX80211_MODE_ADHOC: return rb_str_new2("ADHOC"); break; case TX80211_MODE_INFRA: return rb_str_new2("INFRA"); break; case TX80211_MODE_MASTER: return rb_str_new2("MASTER"); break; case TX80211_MODE_REPEAT: return rb_str_new2("REPEAT"); break; case TX80211_MODE_SECOND: return rb_str_new2("SECOND"); break; case TX80211_MODE_MONITOR: return rb_str_new2("MONITOR"); break; default: return Qnil; break; } } static VALUE lorcon_device_set_mode(VALUE self, VALUE rmode) { struct rldev *rld; char *setmode = StringValuePtr(rmode); int mode = -1; Data_Get_Struct(self, struct rldev, rld); if (strcmp(setmode, "AUTO") == 0) { mode = TX80211_MODE_AUTO; } else if (strcmp(setmode, "ADHOC") == 0) { mode = TX80211_MODE_ADHOC; } else if (strcmp(setmode, "INFRA") == 0) { mode = TX80211_MODE_INFRA; } else if (strcmp(setmode, "MASTER") == 0) { mode = TX80211_MODE_MASTER; } else if (strcmp(setmode, "REPEAT") == 0) { mode = TX80211_MODE_REPEAT; } else if (strcmp(setmode, "SECOND") == 0) { mode = TX80211_MODE_SECOND; } else if (strcmp(setmode, "MONITOR") == 0) { mode = TX80211_MODE_MONITOR; } else { rb_raise(rb_eArgError, "Invalid mode specified: %s", tx80211_geterrstr(&rld->in_tx)); return(Qnil); } return INT2NUM(tx80211_setmode(&rld->in_tx, mode)); } static VALUE lorcon_device_set_functional_mode(VALUE self, VALUE rmode) { struct rldev *rld; char *funcmode = StringValuePtr(rmode); int mode = -1; Data_Get_Struct(self, struct rldev, rld); if (strcmp(funcmode, "RFMON") == 0) { mode = TX80211_FUNCMODE_RFMON; } else if (strcmp(funcmode, "INJECT") == 0) { mode = TX80211_FUNCMODE_INJECT; } else if (strcmp(funcmode, "INJMON") == 0) { mode = TX80211_FUNCMODE_INJMON; } else { rb_raise(rb_eArgError, "Invalid mode specified: %s", tx80211_geterrstr(&rld->in_tx)); return(Qnil); } if (tx80211_setfunctionalmode(&rld->in_tx, mode) != 0) { rb_raise(rb_eArgError, "Lorcon could not set the functional mode: %s", tx80211_geterrstr(&rld->in_tx)); return(Qnil); } return Qtrue; } static VALUE lorcon_device_get_txrate(VALUE self) { struct rldev *rld; int txrate; txrate = tx80211_gettxrate(&rld->in_packet); Data_Get_Struct(self, struct rldev, rld); switch (txrate) { case TX80211_RATE_DEFAULT: return UINT2NUM(0); break; case TX80211_RATE_1MB: return UINT2NUM(1); break; case TX80211_RATE_2MB: return UINT2NUM(2); break; case TX80211_RATE_5_5MB: return UINT2NUM(5); break; case TX80211_RATE_6MB: return UINT2NUM(6); break; case TX80211_RATE_9MB: return UINT2NUM(9); break; case TX80211_RATE_11MB: return UINT2NUM(11); break; case TX80211_RATE_24MB: return UINT2NUM(24); break; case TX80211_RATE_36MB: return UINT2NUM(36); break; case TX80211_RATE_48MB: return UINT2NUM(48); break; case TX80211_RATE_108MB: return UINT2NUM(108); break; default: rb_raise(rb_eArgError, "Lorcon could not determine the tx rate: %s", tx80211_geterrstr(&rld->in_tx)); return(Qnil); } return Qnil; } static VALUE lorcon_device_set_txrate(VALUE self, VALUE rrate) { struct rldev *rld; float settxrate = -1; int txrate = -1; Data_Get_Struct(self, struct rldev, rld); if ((tx80211_getcapabilities(&rld->in_tx) & TX80211_CAP_SETRATE) == 0) { rb_raise(rb_eArgError, "Lorcon does not support setting the tx rate for this card"); return(Qnil); } settxrate = NUM2DBL(rrate); if (settxrate == -1) { txrate = TX80211_RATE_DEFAULT; } else if (settxrate == 1) { txrate = TX80211_RATE_1MB; } else if (settxrate == 2) { txrate = TX80211_RATE_2MB; } else if (settxrate == 5.5) { txrate = TX80211_RATE_5_5MB; } else if (settxrate == 6) { txrate = TX80211_RATE_6MB; } else if (settxrate == 9) { txrate = TX80211_RATE_9MB; } else if (settxrate == 11) { txrate = TX80211_RATE_11MB; } else if (settxrate == 24) { txrate = TX80211_RATE_24MB; } else if (settxrate == 36) { txrate = TX80211_RATE_36MB; } else if (settxrate == 48) { txrate = TX80211_RATE_48MB; } else if (settxrate == 108) { txrate = TX80211_RATE_108MB; } else { rb_raise(rb_eArgError, "Lorcon does not support this rate setting"); return(Qnil); } if (tx80211_settxrate(&rld->in_tx, &rld->in_packet, txrate) < 0) { rb_raise(rb_eArgError, "Lorcon could not set the tx rate: %s", tx80211_geterrstr(&rld->in_tx)); return(Qnil); } return INT2NUM(txrate); } static VALUE lorcon_device_get_modulation(VALUE self) { struct rldev *rld; int mod; Data_Get_Struct(self, struct rldev, rld); mod = tx80211_getmodulation(&rld->in_packet); switch (mod) { case TX80211_MOD_DEFAULT: return rb_str_new2("DEFAULT"); break; case TX80211_MOD_FHSS: return rb_str_new2("FHSS"); break; case TX80211_MOD_DSSS: return rb_str_new2("DSSS"); break; case TX80211_MOD_OFDM: return rb_str_new2("OFDM"); break; case TX80211_MOD_TURBO: return rb_str_new2("TURBO"); break; case TX80211_MOD_MIMO: return rb_str_new2("MIMO"); break; case TX80211_MOD_MIMOGF: return rb_str_new2("MIMOGF"); break; default: rb_raise(rb_eArgError, "Lorcon could not get the modulation value"); return(Qnil); } return(Qnil); } static VALUE lorcon_device_set_modulation(VALUE self, VALUE rmod) { struct rldev *rld; char *setmod = NULL; int mod; Data_Get_Struct(self, struct rldev, rld); if ((tx80211_getcapabilities(&rld->in_tx) & TX80211_CAP_SETMODULATION) == 0) { rb_raise(rb_eArgError, "Lorcon does not support setting the modulation for this card"); return(Qnil); } setmod = StringValuePtr(rmod); if (strcmp(setmod, "DEFAULT") == 0) { mod = TX80211_MOD_DEFAULT; } else if (strcmp(setmod, "FHSS") == 0) { mod = TX80211_MOD_FHSS; } else if (strcmp(setmod, "DSSS") == 0) { mod = TX80211_MOD_DSSS; } else if (strcmp(setmod, "OFDM") == 0) { mod = TX80211_MOD_OFDM; } else if (strcmp(setmod, "TURBO") == 0) { mod = TX80211_MOD_TURBO; } else if (strcmp(setmod, "MIMO") == 0) { mod = TX80211_MOD_MIMO; } else if (strcmp(setmod, "MIMOGF") == 0) { mod = TX80211_MOD_MIMOGF; } else { rb_raise(rb_eArgError, "Lorcon does not support this modulation setting"); return(Qnil); } if (tx80211_setmodulation(&rld->in_tx, &rld->in_packet, mod) < 0) { rb_raise(rb_eArgError, "Lorcon could not set the modulation: %s", tx80211_geterrstr(&rld->in_tx)); return(Qnil); } return INT2NUM(mod); } static VALUE lorcon_device_get_capabilities(VALUE self) { struct rldev *rld; Data_Get_Struct(self, struct rldev, rld); return(lorcon_cap_to_list(tx80211_getcapabilities(&rld->in_tx))); } static VALUE lorcon_device_open(int argc, VALUE *argv, VALUE self) { struct rldev *rld; int ret = 0; int drivertype = INJ_NODRIVER; char *driver, *intf; VALUE rbdriver, rbintf; VALUE obj; rb_scan_args(argc, argv, "2", &rbintf, &rbdriver); driver = STR2CSTR(rbdriver); intf = STR2CSTR(rbintf); obj = Data_Make_Struct(cDevice, struct rldev, 0, lorcon_device_free, rld); drivertype = tx80211_resolvecard(driver); if (drivertype == INJ_NODRIVER) { rb_raise(rb_eArgError, "Lorcon did not recognize the specified driver"); return(Qnil); } if (tx80211_init(&rld->in_tx, intf, drivertype) < 0) { rb_raise(rb_eRuntimeError, "Lorcon could not initialize the interface: %s", tx80211_geterrstr(&rld->in_tx)); return(Qnil); } /* Open the interface to get a socket */ ret = tx80211_open(&rld->in_tx); if (ret < 0) { rb_raise(rb_eRuntimeError, "Lorcon could not open the interface: %s", tx80211_geterrstr(&rld->in_tx)); return(Qnil); } rb_obj_call_init(obj, 0, 0); return(obj); } static VALUE lorcon_device_write(int argc, VALUE *argv, VALUE self) { struct rldev *rld; int ret = 0; int cnt = 0; int dly = 0; VALUE rbbuff, rbcnt, rbdelay; Data_Get_Struct(self, struct rldev, rld); switch(rb_scan_args(argc, argv, "12", &rbbuff, &rbcnt, &rbdelay)) { case 1: rbdelay = INT2NUM(0); case 2: rbcnt = INT2NUM(1); default: break; } cnt = NUM2INT(rbcnt); dly = NUM2INT(rbdelay); rld->in_packet.packet = StringValuePtr(rbbuff); rld->in_packet.plen = RSTRING(rbbuff)->len; for (; cnt > 0; cnt--) { ret = tx80211_txpacket(&rld->in_tx, &rld->in_packet); if (ret < 0) { rb_raise(rb_eRuntimeError, "Lorcon could not transmit packet: %s", tx80211_geterrstr(&rld->in_tx)); return(INT2NUM(ret)); } if (dly > 0) #ifdef _MSC_VER Sleep(dly); #else usleep(dly); #endif } return (rbcnt); } void Init_Lorcon() { mLorcon = rb_define_module("Lorcon"); rb_define_module_function(mLorcon, "drivers", lorcon_driver_list, 0); rb_define_module_function(mLorcon, "version", lorcon_get_version, 0); cDevice = rb_define_class_under(mLorcon, "Device", rb_cObject); rb_define_singleton_method(cDevice, "new", lorcon_device_open, -1); rb_define_method(cDevice, "channel", lorcon_device_get_channel, 0); rb_define_method(cDevice, "channel=", lorcon_device_set_channel, 1); rb_define_method(cDevice, "write", lorcon_device_write, -1); rb_define_method(cDevice, "mode", lorcon_device_get_mode, 0); rb_define_method(cDevice, "mode=", lorcon_device_set_mode, 1); rb_define_method(cDevice, "fmode=", lorcon_device_set_functional_mode, 1); rb_define_method(cDevice, "txrate", lorcon_device_get_txrate, 0); rb_define_method(cDevice, "txrate=", lorcon_device_set_txrate, 1); rb_define_method(cDevice, "modulation", lorcon_device_get_modulation, 0); rb_define_method(cDevice, "modulation=", lorcon_device_set_modulation, 1); rb_define_method(cDevice, "capabilities", lorcon_device_get_capabilities, 0); }