diff --git a/README.md b/README.md index 4a32078..36f6447 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,13 @@ # smrtlink Command-Line Tool which might in the future be able to configure TP-Link Easy Smart Switches. -The usage is loosely based on the swconfig utility. +The usage is loosely based on the swconfig utility. -###dependencys +### dependencys libboost-filesystem-dev - libboost-system-dev \ No newline at end of file + libboost-system-dev + +### compatible devices ++ TL-SG105E ++ TL-SG108E ++ TL-SG1016DE (not tested) ++ TL-SG1024DE (not tested) diff --git a/src/Constant.h b/src/Constant.h new file mode 100644 index 0000000..31e73fc --- /dev/null +++ b/src/Constant.h @@ -0,0 +1,66 @@ +/* + * Options.h + * + * Created on: 11.09.2015 + * Author: jdi + */ + +#ifndef OPTIONS_H_ +#define OPTIONS_H_ + +#include "Types.h" + +#define VERSION "smrtlink (v1.1 Linux)\n" +#define USAGE "usage: %s [-bdhjrvswx] [-i interface] [-u [password:]username]\n\ + [-p password] \n\n" +#define HELP "\ + Option Summary:\n\ + -h --help This help text\n\ + -v --version Display version of this tool\n\ + -d --debug [n] Show debugging messages\n\ + -r switch ports to emulate switch while sniffing\n\ + -b --header Show header\n\ + -x --hex Display Packets as Hex String\n\ + -j --json Display Packets as JSON\n\ + -i --interface only use one Interface\n\ + -u --user <[password:]username>\n\ + -p --password \n\ + Login with Username and Password\n\ + -f --file choose a settings file\n\n\ + -t --timeout Timeout in milliseconds. Default: 180\n\ + -I --interactive Not yet implemented\n\ + -O --stdout Not yet implemented\n\ + -w --wait Not yet implemented: blocking until operation is completed\n\ + -s --permanent Not yet implemented: make changes immediately permanent\n\n\ + Command Summary:\n\ + help This help text\n\ + list list all connected switches\n\ + sniff [type:] []\n\ + capture and display all incoming or outgoing packets\n\ + depending on the --reverse option\n\ + encode use encoding algorithm on hex data separated by colon\n\ + get Not yet implemented\n\ + set Not yet implemented\n\ + get|save Not yet implemented: save config to file\n\ + set|restore Not yet implemented: restore onfig from file\n\ + flash Not yet implemented: replace firmware\n\ + reboot Not yet implemented\n\ + reset Not yet implemented\n\n\ + ### for questions please contact ###\n\n" +//TODO +/* + * Stdin + * socketmode + * + */ + +#define FLAG_HEX 1 +#define FLAG_REVERSE 2 +#define FLAG_HEADER 4 +#define FLAG_PERMANENT 8 +#define FLAG_WAIT 16 +#define FLAG_DEBUG 32 + +extern Options options; + +#endif /* OPTIONS_H_ */ diff --git a/src/File.cpp b/src/File.cpp index 654bca2..0e6e944 100644 --- a/src/File.cpp +++ b/src/File.cpp @@ -7,7 +7,7 @@ #include #include "File.h" -#include "Options.h" +#include "Constant.h" std::string File::read() { if (!fs::exists(home)) { diff --git a/src/Host.cpp b/src/Host.cpp index 83a06b4..1fbba26 100644 --- a/src/Host.cpp +++ b/src/Host.cpp @@ -21,7 +21,7 @@ #include #include -#include "Options.h" +#include "Constant.h" #include "Host.h" #include "Types.h" diff --git a/src/Program.cpp b/src/Program.cpp index 70b7e74..ecf39ad 100644 --- a/src/Program.cpp +++ b/src/Program.cpp @@ -7,14 +7,14 @@ #include #include -#include "Options.h" +#include "Constant.h" #include "Program.h" #include "File.h" #include "Host.h" #include "Socket.h" #include "Switch.h" #include "Packet.h" -#include "Lookup.h" +#include "lookup.h" #include "table.h" int printHeader(Packet p) { @@ -44,10 +44,22 @@ int printPacket(Packet p) { std::cout << "+\t" << s->name << " = " << &d.value[0] << "\n"; break; + case table::BOOL: + std::cout << "+\t" << s->name << " = " << (d.value[0]?"YES":"NO") + << "\n"; + break; case table::HEX: std::cout << "+\t" << s->name << " = " << d.value << "\n"; break; + case table::DEC: + std::cout << "+\t" << s->name << " = "; + if (d.value.size() > 0) + std::cout << std::dec << (unsigned) d.value[0]; + for (unsigned i = 1; i < d.value.size(); i++) + std::cout << std::dec << "." << (unsigned) d.value[i]; + std::cout << "\n"; + break; case table::ACTION: std::cout << "Error:" << s->name << " is marked as 'action' but carries payload." @@ -56,6 +68,7 @@ int printPacket(Packet p) { default: std::cout << "+\t" << s->name << " = " << d.value << "\n"; + break; } } else { //empty std::cout << std::dec << ">\t" << s->name << "\n"; @@ -149,17 +162,13 @@ int Program::getProperty() { p.setPayload( { }); bytes b = p.getBytes(); p.encode(b); - std::cout << "count-x:" << sock.use_count() << "\n"; auto s = sock; try { sock->setHostIp(host.getIp()); sock->init(DST_PORT, SRC_PORT); - - std::cout << "count-y:" << sock.use_count() << "\n"; sock->callback = [this](Packet a) { auto s = sock; - std::cout<<"count-z:"<send(c); - - std::cout<<"count-a:"<send(b); @@ -245,6 +254,11 @@ int Program::reset() { return 0; } +int Program::ping(std::function){ + + return 0; +} + void Program::init() { if (options.interface.compare("") == 0) options.interface = host.getIface(); diff --git a/src/Program.h b/src/Program.h index 1df58ec..1bd97da 100644 --- a/src/Program.h +++ b/src/Program.h @@ -19,6 +19,7 @@ private: std::shared_ptr io_service; std::shared_ptr sock; Host host = Host(); + int ping(std::function); public: Program() { io_service = std::make_shared(); diff --git a/src/Socket.cpp b/src/Socket.cpp index 7ef01d4..942f563 100644 --- a/src/Socket.cpp +++ b/src/Socket.cpp @@ -9,7 +9,7 @@ #include #include "Socket.h" #include "Packet.h" -#include "Options.h" +#include "Constant.h" #include "Host.h" #include "Types.h" diff --git a/src/Switch-Json.cpp b/src/Switch-Json.cpp new file mode 100644 index 0000000..21f1477 --- /dev/null +++ b/src/Switch-Json.cpp @@ -0,0 +1,98 @@ +/* + * Switch.cpp + * + * Created on: 29.09.2015 + * Author: jdi + */ + +#include +#include "Types.h" +#include "Switch.h" +#include "jsonNode.h" +#include "Constant.h" +#include "table.h" + +int Switch::parse(std::string str) { + + if (json.Parse(str.c_str()).HasParseError()) + return 1; + if (options.flags & FLAG_DEBUG) + std::cout << "\nParsing to document succeeded.\n"; + + if (json.IsObject()) { + if (json.HasMember("hostname")) + settings.hostname = json["hostname"].GetString(); + if (json.HasMember("type")) + device.type = json["type"].GetString(); + if (json.HasMember("hardware_version")) + device.hardware_version = json["hardware_version"].GetString(); + if (json.HasMember("firmware_version")) + device.hardware_version = json["firmware_version"].GetString(); + if (json.HasMember("ports") && json["ports"].IsArray()) { + const rapidjson::Value& a = json["ports"]; + for (rapidjson::SizeType i = 0; i < a.Size(); i++) + if (a[i].IsObject()) { + port p; + if (a[i].HasMember("id") && a[i]["id"].IsInt()) { + p.id = a[i]["id"].GetInt(); + std::cout << a[i]["id"].GetInt() << "\n"; + } + ports.push_back(p); + } + } + if (json.HasMember("vlans") && json["vlans"].IsArray()) { + const rapidjson::Value& a = json["vlans"]; + for (rapidjson::SizeType i = 0; i < a.Size(); i++) + if (a[i].IsObject()) { + vlan v; + if (a[i].HasMember("name") && a[i]["name"].IsString()) { + v.name = a[i]["name"].GetString(); + std::cout << a[i]["name"].GetString() << "\n"; + } + vlans.push_back(v); + } + } + + } + + /* + + + { + const rapidjson::Value& a = json["a"]; + assert(a.IsArray()); + for (rapidjson::SizeType i = 0; i < a.Size(); i++) + printf("a[%d] = %d\n", i, a[i].GetInt()); + + int y = a[0].GetInt(); + (void) y; + + */ + return 0; +} + +std::string Switch::toString() { + + if (!json.IsObject()) { + json.SetObject(); + } + rapidjson::Document::AllocatorType& allocator = json.GetAllocator(); + + json.AddMember("hostname", jsonNode(settings.hostname, json), allocator); + json.AddMember("ip", jsonNode(settings.ip_addr, json), allocator); + json.AddMember("netmask", jsonNode(settings.ip_mask, json), allocator); + json.AddMember("gateway", jsonNode(settings.gateway, json), allocator); + json.AddMember("type", jsonNode(device.type, json), allocator); + json.AddMember("hardware_version", jsonNode(device.hardware_version, json), + allocator); + json.AddMember("firmware_version", jsonNode(device.firmware_version, json), + allocator); + json.AddMember("ports", jsonNode(ports, json), allocator); + json.AddMember("vlans", jsonNode(vlans, json), allocator); + + rapidjson::StringBuffer sb; + rapidjson::PrettyWriter writer(sb); + json.Accept(writer); + return sb.GetString(); +} + diff --git a/src/Switch.cpp b/src/Switch.cpp index 00d1a55..9b48777 100644 --- a/src/Switch.cpp +++ b/src/Switch.cpp @@ -8,9 +8,8 @@ #include #include "Types.h" #include "Switch.h" -#include "Lookup.h" -#include "jsonNode.h" -#include "Options.h" +#include "lookup.h" +#include "Constant.h" #include "table.h" int Switch::parse(datasets arr) { @@ -22,129 +21,48 @@ int Switch::parse(datasets arr) { int Switch::parse(dataset d) { auto lookup = (options.flags & FLAG_REVERSE) ? snd_lookup : rcv_lookup; - if (d.type == lookup["type"]) { - device.type = d.value; + std::string id = lookup.exists(d.type)?lookup[d.type]:"unknown"; + switch(d.type){ + case TYPE: + device.type = d.value; + break; } - if (d.type == lookup["mac"]) { + + if (id == "mac") { device.mac = d.value; } - if (d.type == lookup["firmware_version"]) { + else if (d.type == "firmware_version") { device.firmware_version = d.value; } - if (d.type == lookup["hardware_version"]) { + else if (id == "hardware_version") { device.hardware_version = d.value; } - if (d.type == lookup["ports"]) { + else if (id == "ports") { device.ports = d.value[0]; } - if (d.type == lookup["hostname"]) { + else if (id == "hostname") { settings.hostname = d.value; } - if (d.type == lookup["ip_addr"]) { + else if (id == "ip_addr") { settings.ip_addr = d.value; } - if (d.type == lookup["ip_mask"]) { + else if (id == "ip_mask") { settings.ip_mask = d.value; } - if (d.type == lookup["gateway"]) { + else if (id == "gateway") { settings.gateway = d.value; } - if (d.type == lookup["dhcp"]) { + else if (id == "dhcp_enabled") { settings.dhcp = d.value[0]; } - if (d.type == lookup["loop_prevention"]) { + else if (id == "loop_prevention") { settings.loop_prevention = d.value[0]; } - if (d.type == lookup["qos_basic_enabled"]) { + else if (id == "qos_basic_enabled") { settings.qos_enabled = d.value[0]; } - if (d.type == lookup["vlan_enabled"]) { + else if (id == "vlan_enabled") { settings.vlan_enabled = d.value[0]; } return 0; } - -int Switch::parse(std::string str) { - - if (json.Parse(str.c_str()).HasParseError()) - return 1; - if (options.flags & FLAG_DEBUG) - std::cout << "\nParsing to document succeeded.\n"; - - if (json.IsObject()) { - if (json.HasMember("hostname")) - settings.hostname = json["hostname"].GetString(); - if (json.HasMember("type")) - device.type = json["type"].GetString(); - if (json.HasMember("hardware_version")) - device.hardware_version = json["hardware_version"].GetString(); - if (json.HasMember("firmware_version")) - device.hardware_version = json["firmware_version"].GetString(); - if (json.HasMember("ports") && json["ports"].IsArray()) { - const rapidjson::Value& a = json["ports"]; - for (rapidjson::SizeType i = 0; i < a.Size(); i++) - if (a[i].IsObject()) { - port p; - if (a[i].HasMember("id") && a[i]["id"].IsInt()) { - p.id = a[i]["id"].GetInt(); - std::cout << a[i]["id"].GetInt() << "\n"; - } - ports.push_back(p); - } - } - if (json.HasMember("vlans") && json["vlans"].IsArray()) { - const rapidjson::Value& a = json["vlans"]; - for (rapidjson::SizeType i = 0; i < a.Size(); i++) - if (a[i].IsObject()) { - vlan v; - if (a[i].HasMember("name") && a[i]["name"].IsString()) { - v.name = a[i]["name"].GetString(); - std::cout << a[i]["name"].GetString() << "\n"; - } - vlans.push_back(v); - } - } - - } - - /* - - - { - const rapidjson::Value& a = json["a"]; - assert(a.IsArray()); - for (rapidjson::SizeType i = 0; i < a.Size(); i++) - printf("a[%d] = %d\n", i, a[i].GetInt()); - - int y = a[0].GetInt(); - (void) y; - - */ - return 0; -} - -std::string Switch::toString() { - - if (!json.IsObject()) { - json.SetObject(); - } - rapidjson::Document::AllocatorType& allocator = json.GetAllocator(); - - json.AddMember("hostname", jsonNode(settings.hostname, json), allocator); - json.AddMember("ip", jsonNode(settings.ip_addr, json), allocator); - json.AddMember("netmask", jsonNode(settings.ip_mask, json), allocator); - json.AddMember("gateway", jsonNode(settings.gateway, json), allocator); - json.AddMember("type", jsonNode(device.type, json), allocator); - json.AddMember("hardware_version", jsonNode(device.hardware_version, json), - allocator); - json.AddMember("firmware_version", jsonNode(device.firmware_version, json), - allocator); - json.AddMember("ports", jsonNode(ports, json), allocator); - json.AddMember("vlans", jsonNode(vlans, json), allocator); - - rapidjson::StringBuffer sb; - rapidjson::PrettyWriter writer(sb); - json.Accept(writer); - return sb.GetString(); -} - diff --git a/src/Switch.h b/src/Switch.h index 0a5c7ea..88a3351 100644 --- a/src/Switch.h +++ b/src/Switch.h @@ -17,6 +17,10 @@ #define DEFAULT_USER "admin" #define DEFAULT_PASS "admin" +enum CntStatus { + OPEN, SHORT +}; + struct vlan { int vlan_id; std::string name; @@ -24,17 +28,34 @@ struct vlan { std::vector untagged_member; }; +struct trunk { + int trunk_id; + std::vector member; +}; + struct port { byte id; byte status; int pvid; - //port_settings + struct { + //port_settings + } settings; + struct { + //port_statistics + } stats; + struct { + //bandwidth_control_ingress + //bandwidth_control_egress + } bw_control; + struct { + //storm_control + } storm_control; + struct { + CntStatus status; + int fault_distace; + } test; //qos_basic - //bandwidth_control_1 - //bandwidth_control_2 - //storm_control - //port_statistics - //cable_test + }; class Switch { @@ -45,6 +66,7 @@ public: int parse(dataset); int parse(std::string); std::string toString(); + struct { std::string type; std::string hardware_version; @@ -63,7 +85,9 @@ public: bool loop_prevention; bool qos_enabled; bool vlan_enabled; + //mtu_vlan } settings; + private: rapidjson::Document json; std::vector vlans; diff --git a/src/bytes.cpp b/src/bytes.cpp index bdc8c9d..9dac956 100644 --- a/src/bytes.cpp +++ b/src/bytes.cpp @@ -7,22 +7,23 @@ #include "bytes.h" -bytes::bytes(std::string d) { - vector(); +bytes bytes::readHex(std::string s){ + vector ret; std::string delimiter = ":"; std::string token; size_t pos = 0; int hex; byte b; - resize(0); - while ((pos = d.find(delimiter)) != std::string::npos) { - token = d.substr(0, pos); + ret.resize(0); + while ((pos = s.find(delimiter)) != std::string::npos) { + token = s.substr(0, pos); sscanf(token.c_str(), "%x", &hex); - d.erase(0, pos + delimiter.length()); + s.erase(0, pos + delimiter.length()); b = hex & 0xFF; - push_back(b); + ret.push_back(b); } - sscanf(d.c_str(), "%x", &hex); + sscanf(s.c_str(), "%x", &hex); b = hex & 0xFF; - push_back(b); + ret.push_back(b); + return ret; } diff --git a/src/bytes.h b/src/bytes.h index dcc0ec9..eb129d6 100644 --- a/src/bytes.h +++ b/src/bytes.h @@ -24,11 +24,11 @@ public: using vector::operator[]; bytes() { } - bytes(int n) : - vector(n) { + bytes(int n) : vector(n){ } - bytes(std::string); + bytes(std::string d) : vector(d.begin(), d.end()){ + } bytes(std::initializer_list s) { @@ -42,9 +42,7 @@ public: this->insert(this->begin(), B.begin(), B.end()); } - bytes readHex(std::string s){ - return bytes(s); - } + bytes readHex(std::string); bytes operator=(const vector &B) { this->reserve(B.size()); diff --git a/src/lookup.h b/src/lookup.h new file mode 100644 index 0000000..4b72515 --- /dev/null +++ b/src/lookup.h @@ -0,0 +1,17 @@ +enum { +#define LOOKUP_SET(id, num, type) FOO_ ## id = num, +#include "lookup/general.lst" +}; + +static table rcv_lookup { +#define LOOKUP_SET(id, num, type) { FOO_ ## id, table::type, #id }, +#include "lookup/rcv.lst" +#include "lookup/general.lst" +}; + +static table snd_lookup { +#define LOOKUP_SET(id, num, type) { FOO_ ## id, table::type, #id }, +#include "lookup/snd.lst" +#include "lookup/general.lst" +}; + diff --git a/src/lookup/general.lst b/src/lookup/general.lst new file mode 100644 index 0000000..537b307 --- /dev/null +++ b/src/lookup/general.lst @@ -0,0 +1,24 @@ +LOOKUP_SET(IGMP_SNOOPING, 4352, HEX) //??? +LOOKUP_SET(PORTS_SETTINGS, 4096, HEX) //+per port +LOOKUP_SET(PORT_TRUNK, 4608, HEX) //byte[5] last byte bitmask?? + +LOOKUP_SET(MTU_VLAN, 8192, HEX) //byte[2] first byte bool,second byte port id +LOOKUP_SET(PORT_VLAN_ENABLED, 8448, BOOL) //open page +LOOKUP_SET(PORT_VLAN, 8449, HEX) +LOOKUP_SET(PORT_VLAN_MAX, 8450, DEC) +LOOKUP_SET(VLAN_ENABLED, 8704, BOOL) //+bool byte +LOOKUP_SET(VLAN, 8705, HEX) //+one set per vlan +LOOKUP_SET(VLAN_PVID, 8706, HEX) //+per port +LOOKUP_SET(VLAN_FOOOO, 8707, DEC) //???? + +LOOKUP_SET(QOS_BASIC_ENABLED, 12288, BOOL) //+bool = QoS Mod +LOOKUP_SET(QOS_BASIC, 12289, HEX) //+per port ??? +LOOKUP_SET(BANDWIDTH_CONTROL_INGRESS, 12544, HEX) //+per port ??? +LOOKUP_SET(BANDWIDTH_CONTROL_EGRESS, 12545, HEX) //+per port ??? +LOOKUP_SET(STORM_CONTROL, 12800, HEX) //+per port ??? +LOOKUP_SET(PORT_MIRROR, 16640, HEX) //byte[10] second byte port id??? +LOOKUP_SET(PORT_STATISTICS, 16384, HEX) //+per port ??? +LOOKUP_SET(CABLE_TEST, 16896, HEX) //+per port ??? +LOOKUP_SET(LOOP_PREVENTION, 17152, BOOL) //+bool byte + +#undef LOOKUP_SET \ No newline at end of file diff --git a/src/lookup/rcv.lst b/src/lookup/rcv.lst new file mode 100644 index 0000000..21d75fd --- /dev/null +++ b/src/lookup/rcv.lst @@ -0,0 +1,15 @@ +LOOKUP_SET(TYPE, 1, STRING) //+string +LOOKUP_SET(HOSTNAME, 2, STRING) //+string +LOOKUP_SET(MAC, 3, HEX) //+byte[6] +LOOKUP_SET(IP_ADDR, 4, DEC) //+byte[4] +LOOKUP_SET(IP_MASK, 5, DEC) //+byte[4] +LOOKUP_SET(GATEWAY, 6, DEC) //+byte[4] +LOOKUP_SET(FIRMWARE_VERSION, 7, STRING) +LOOKUP_SET(HARDWARE_VERSION, 8, STRING) +LOOKUP_SET(DHCP_ENABLED, 9, BOOL) //+bool byte +LOOKUP_SET(PORTS, 10, DEC) //+byte, maybe number of ports + + +LOOKUP_SET(PORT_VLAN_FOOOOO, 2101, HEX) + + diff --git a/src/lookup/snd.lst b/src/lookup/snd.lst new file mode 100644 index 0000000..4169dac --- /dev/null +++ b/src/lookup/snd.lst @@ -0,0 +1,18 @@ +LOOKUP_SET(SYSTEM_INFO, 2, HEX) //page sysinfo +LOOKUP_SET(IP_CONFIG, 9, HEX) //page sysinfo +LOOKUP_SET(PORTS, 10, HEX) //after login + + +LOOKUP_SET(LOGIN_USER, 512, STRING) //string +LOOKUP_SET(NEW_USER, 513, STRING) //string +LOOKUP_SET(LOGIN_PASSWORD, 514, STRING) //string +LOOKUP_SET(NEW_PASSWORD, 515, STRING) //string +LOOKUP_SET(REBOOT, 773, BOOL) //bool byte = save config + +LOOKUP_SET(RESET, 1280, ACTION) // +LOOKUP_SET(FLASH, 1536, ACTION) //update firmware +LOOKUP_SET(VLAN_FOOOOOO, 2200, HEX) //vlan +LOOKUP_SET(SAVE, 2304, ACTION) //save +LOOKUP_SET(PING, 2305, ACTION) //sent before SET ??? + + diff --git a/src/smrtlink.cpp b/src/smrtlink.cpp index c23c0a0..8a821ee 100644 --- a/src/smrtlink.cpp +++ b/src/smrtlink.cpp @@ -16,9 +16,10 @@ #include #include -#include "Options.h" +#include "Constant.h" #include "Host.h" #include "Program.h" +#include "Switch.h" #define no_argument 0 #define required_argument 1 @@ -33,6 +34,9 @@ constexpr unsigned int caseArg(const char* str, int h = 0) { int main(int argc, char *argv[]) { int opt, index; + options.user = DEFAULT_USER; + options.password = DEFAULT_PASS; + const struct option longopts[] = { { "version", no_argument, 0, 'v' }, { "help", no_argument, 0, 'h' }, { "reverse", no_argument, 0, 'r' }, { "permanent", no_argument, 0, 's' }, { "debug", optional_argument, 0, diff --git a/src/table.h b/src/table.h index f9171a6..54f8a91 100644 --- a/src/table.h +++ b/src/table.h @@ -13,7 +13,7 @@ class table { public: - enum F {STRING,HEX,DEC,ACTION,EMPTY}; + enum F {STRING,HEX,DEC,ACTION,BOOL,EMPTY}; struct set { short type; F format;