SPtr<TSrvMsg> TSrvIfaceMgr::decodeRelayForw(SPtr<TSrvIfaceIface> ptrIface, SPtr<TIPv6Addr> peer, char * buf, int bufsize) { SPtr<TIPv6Addr> linkAddrTbl[HOP_COUNT_LIMIT]; SPtr<TIPv6Addr> peerAddrTbl[HOP_COUNT_LIMIT]; SPtr<TSrvOptInterfaceID> interfaceIDTbl[HOP_COUNT_LIMIT]; int hopTbl[HOP_COUNT_LIMIT]; List(TOptGeneric) echoListTbl[HOP_COUNT_LIMIT]; SPtr<TSrvIfaceIface> relayIface; int relays=0; // number of nested RELAY_FORW messages SPtr<TOptVendorData> remoteID = 0; SPtr<TOptOptionRequest> echo = 0; SPtr<TOptGeneric> gen = 0; char * relay_buf = buf; int relay_bufsize = bufsize; for (int j=0;j<HOP_COUNT_LIMIT; j++) echoListTbl[j].clear(); while (bufsize>0 && buf[0]==RELAY_FORW_MSG) { /* decode RELAY_FORW message */ if (bufsize < 34) { Log(Warning) << "Truncated RELAY_FORW message received." << LogEnd; return 0; } SPtr<TSrvOptInterfaceID> ptrIfaceID; ptrIfaceID = 0; char type = buf[0]; if (type!=RELAY_FORW_MSG) return 0; int hopCount = buf[1]; int optRelayCnt = 0; int optIfaceIDCnt = 0; SPtr<TIPv6Addr> linkAddr = new TIPv6Addr(buf+2,false); SPtr<TIPv6Addr> peerAddr = new TIPv6Addr(buf+18, false); buf+=34; bufsize-=34; // options: only INTERFACE-ID and RELAY_MSG are allowed while (bufsize>=4) { unsigned short code = readUint16(buf); buf += sizeof(uint16_t); bufsize -= sizeof(uint16_t); int len = readUint16(buf); buf += sizeof(uint16_t); bufsize -= sizeof(uint16_t); if (len > bufsize) { Log(Warning) << "Truncated option " << code << ": " << bufsize << " bytes remaining, but length is " << len << "." << LogEnd; return 0; } switch (code) { case OPTION_INTERFACE_ID: if (bufsize<4) { Log(Warning) << "Truncated INTERFACE_ID option (length: " << bufsize << ") in RELAY_FORW message. Message dropped." << LogEnd; return 0; } ptrIfaceID = new TSrvOptInterfaceID(buf, len, 0); optIfaceIDCnt++; break; case OPTION_RELAY_MSG: relay_buf = buf; relay_bufsize = len; optRelayCnt++; break; case OPTION_REMOTE_ID: remoteID = new TOptVendorData(OPTION_REMOTE_ID, buf, len, 0); break; case OPTION_ERO: Log(Debug) << "Echo Request received in RELAY_FORW." << LogEnd; echo = new TOptOptionRequest(OPTION_ERO, buf, len, 0); break; default: gen = new TOptGeneric(code, buf, len, 0); echoListTbl[relays].append(gen); } buf += len; bufsize -= len; } // remember options to be echoed echoListTbl[relays].first(); while (gen = echoListTbl[relays].get()) { if (!echo) { Log(Warning) << "Invalid option (" << gen->getOptType() << ") in RELAY_FORW message was ignored." << LogEnd; echoListTbl[relays].del(); } else { if (!echo->isOption(gen->getOptType())) { Log(Warning) << "Invalid option (" << gen->getOptType() << ") in RELAY_FORW message was ignored." << LogEnd; echoListTbl[relays].del(); } else { Log(Info) << "Option " << gen->getOptType() << " will be echoed back." << LogEnd; } } } // remember those links linkAddrTbl[relays] = linkAddr; peerAddrTbl[relays] = peerAddr; interfaceIDTbl[relays] = ptrIfaceID; hopTbl[relays] = hopCount; relays++; if (relays> HOP_COUNT_LIMIT) { Log(Error) << "Message is nested more than allowed " << HOP_COUNT_LIMIT << " times. Message dropped." << LogEnd; return 0; } if (optRelayCnt!=1) { Log(Error) << optRelayCnt << " RELAY_MSG options received, but exactly one was expected. Message dropped." << LogEnd; return 0; } if (optIfaceIDCnt>1) { Log(Error) << "More than one (" << optIfaceIDCnt << ") interface-ID options received, but at most 1 was expected. Message dropped." << LogEnd; return 0; } Log(Info) << "RELAY_FORW was decapsulated: link=" << linkAddr->getPlain() << ", peer=" << peerAddr->getPlain(); bool guessMode = SrvCfgMgr().guessMode(); if (ptrIfaceID) { // find relay interface based on the interface-id option Log(Cont) << ", interfaceID len=" << ptrIfaceID->getSize() << LogEnd; relayIface = ptrIface->getRelayByInterfaceID(ptrIfaceID); if (!relayIface) { if (!guessMode) { Log(Error) << "Unable to find relay interface with interfaceID=" << ptrIfaceID->getPlain() << " defined on the " << ptrIface->getName() << "/" << ptrIface->getID() << " interface." << LogEnd; return 0; } } } else { // find relay interface based on the link address Log(Cont) << ", interfaceID option missing." << LogEnd; Log(Warning) << "InterfaceID option missing, trying to find proper interface using link address: " << linkAddr->getPlain() << " (expect troubles)."<< LogEnd; relayIface = ptrIface->getRelayByLinkAddr(linkAddr); if (!relayIface) { Log(Error) << "Unable to find relay interface using link address: " << linkAddr->getPlain() << LogEnd; if (!guessMode) { return 0; } } } if (!relayIface && guessMode) { relayIface = ptrIface->getAnyRelay(); if (!relayIface) { Log(Error) << "Guess-mode: Unable to find any relays on " << ptrIface->getFullName() << LogEnd; return 0; } interfaceIDTbl[relays] = -1; Log(Notice) << "Guess-mode: Relayed interface guessed as " << relayIface->getFullName() << LogEnd; } // now switch to relay interface ptrIface = relayIface; buf = relay_buf; bufsize = relay_bufsize; } SPtr<TSrvMsg> msg = this->decodeMsg(ptrIface, peer, relay_buf, relay_bufsize); for (int i=0; i<relays; i++) { msg->addRelayInfo(linkAddrTbl[i], peerAddrTbl[i], hopTbl[i], interfaceIDTbl[i], echoListTbl[i]); } if (remoteID) { Log(Debug) << "RemoteID received: vendor=" << remoteID->getVendor() << ", length=" << remoteID->getVendorDataLen() << "." << LogEnd; msg->setRemoteID(remoteID); remoteID = 0; remoteID = msg->getRemoteID(); PrintHex("RemoteID:", remoteID->getVendorData(), remoteID->getVendorDataLen()); } return (Ptr*)msg; }
SPtr<TSrvMsg> TSrvIfaceMgr::decodeRelayForw(SPtr<TIfaceIface> physicalIface, SPtr<TIPv6Addr> peer, char * buf, int bufsize) { SPtr<TIPv6Addr> linkAddrTbl[HOP_COUNT_LIMIT]; SPtr<TIPv6Addr> peerAddrTbl[HOP_COUNT_LIMIT]; int hopTbl[HOP_COUNT_LIMIT]; TOptList echoListTbl[HOP_COUNT_LIMIT]; int relays=0; // number of nested RELAY_FORW messages SPtr<TOptVendorData> remoteID = 0; SPtr<TOptOptionRequest> echo = 0; SPtr<TOpt> gen = 0; int ifindex = -1; char * relay_buf = buf; int relay_bufsize = bufsize; for (int j=0;j<HOP_COUNT_LIMIT; j++) echoListTbl[j].clear(); string how_found = ""; while (bufsize>0 && buf[0]==RELAY_FORW_MSG) { /* decode RELAY_FORW message */ if (bufsize < 34) { Log(Warning) << "Truncated RELAY_FORW message received." << LogEnd; return 0; } SPtr<TSrvOptInterfaceID> ptrIfaceID = 0; how_found = ""; char type = buf[0]; if (type!=RELAY_FORW_MSG) return 0; int hopCount = buf[1]; int optRelayCnt = 0; int optIfaceIDCnt = 0; SPtr<TIPv6Addr> linkAddr = new TIPv6Addr(buf+2,false); SPtr<TIPv6Addr> peerAddr = new TIPv6Addr(buf+18, false); buf+=34; bufsize-=34; // options: only INTERFACE-ID and RELAY_MSG are allowed while (bufsize>=4) { unsigned short code = readUint16(buf); buf += sizeof(uint16_t); bufsize -= sizeof(uint16_t); int len = readUint16(buf); buf += sizeof(uint16_t); bufsize -= sizeof(uint16_t); gen = 0; if (len > bufsize) { Log(Warning) << "Truncated option " << code << ": " << bufsize << " bytes remaining, but length is " << len << "." << LogEnd; return 0; } switch (code) { case OPTION_INTERFACE_ID: if (bufsize < 1) { Log(Warning) << "Truncated INTERFACE_ID option (length: " << bufsize << ") in RELAY_FORW message. Message dropped." << LogEnd; return 0; } ptrIfaceID = new TSrvOptInterfaceID(buf, len, 0); gen = (Ptr*)ptrIfaceID; optIfaceIDCnt++; break; case OPTION_RELAY_MSG: relay_buf = buf; relay_bufsize = len; optRelayCnt++; break; case OPTION_REMOTE_ID: gen = new TOptVendorData(OPTION_REMOTE_ID, buf, len, 0); break; case OPTION_ERO: Log(Debug) << "Echo Request received in RELAY_FORW." << LogEnd; gen = new TOptOptionRequest(OPTION_ERO, buf, len, 0); break; default: gen = new TOptGeneric(code, buf, len, 0); } if (gen) { echoListTbl[relays].push_back(gen); } buf += len; bufsize -= len; } #if 0 // remember options to be echoed echoListTbl[relays].first(); while (gen = echoListTbl[relays].get()) { if (!echo) { Log(Warning) << "Invalid option (" << gen->getOptType() << ") in RELAY_FORW message was ignored." << LogEnd; echoListTbl[relays].del(); } else { if (!echo->isOption(gen->getOptType())) { Log(Warning) << "Invalid option (" << gen->getOptType() << ") in RELAY_FORW message was ignored." << LogEnd; echoListTbl[relays].del(); } else { Log(Info) << "Option " << gen->getOptType() << " will be echoed back." << LogEnd; } } } #endif // remember those links linkAddrTbl[relays] = linkAddr; peerAddrTbl[relays] = peerAddr; hopTbl[relays] = hopCount; relays++; if (relays> HOP_COUNT_LIMIT) { Log(Error) << "Message is nested more than allowed " << HOP_COUNT_LIMIT << " times. Message dropped." << LogEnd; return 0; } if (optRelayCnt!=1) { Log(Error) << optRelayCnt << " RELAY_MSG options received, but exactly one was " << "expected. Message dropped." << LogEnd; return 0; } if (optIfaceIDCnt>1) { Log(Error) << "More than one (" << optIfaceIDCnt << ") interface-ID options received, but exactly 1 was expected. " << "Message dropped." << LogEnd; return 0; } Log(Info) << "RELAY_FORW was decapsulated: link=" << linkAddr->getPlain() << ", peer=" << peerAddr->getPlain(); // --- selectSubnet() starts here --- bool guessMode = SrvCfgMgr().guessMode(); // First try to find a relay based on the interface-id option if (ptrIfaceID) { Log(Cont) << ", interfaceID len=" << ptrIfaceID->getSize() << LogEnd; ifindex = SrvCfgMgr().getRelayByInterfaceID(ptrIfaceID); if (ifindex == -1) { Log(Debug) << "Unable to find relay interface with interfaceID=" << ptrIfaceID->getPlain() << " defined on the " << physicalIface->getFullName() << " interface." << LogEnd; } else { how_found = "using interface-id=" + ptrIfaceID->getPlain(); } } else { Log(Cont) << ", no interface-id option." << LogEnd; } // then try to find a relay based on the link address if (ifindex == -1) { ifindex = SrvCfgMgr().getRelayByLinkAddr(linkAddr); if (ifindex == -1) { Log(Info) << "Unable to find relay interface using link address: " << linkAddr->getPlain() << LogEnd; } else { how_found = string("using link-addr=") + linkAddr->getPlain(); } } // the last hope - use guess-mode to get any relay if ((ifindex == -1) && guessMode) { ifindex = SrvCfgMgr().getAnyRelay(); if (ifindex != -1) { how_found = "using guess-mode"; } } // --- selectSubnet() ends here --- // now switch to relay interface buf = relay_buf; bufsize = relay_bufsize; } if (ifindex == -1) { Log(Warning) << "Unable to find appropriate interface for this RELAY-FORW." << LogEnd; return 0; } else { SPtr<TSrvCfgIface> cfgIface = SrvCfgMgr().getIfaceByID(ifindex); Log(Notice) << "Found relay " << cfgIface->getFullName() << " by " << how_found << LogEnd; } SPtr<TSrvMsg> msg = decodeMsg(ifindex, peer, relay_buf, relay_bufsize); if (!msg) { return 0; } for (int i=0; i<relays; i++) { msg->addRelayInfo(linkAddrTbl[i], peerAddrTbl[i], hopTbl[i], echoListTbl[i]); } msg->setPhysicalIface(physicalIface->getID()); if (remoteID) { Log(Debug) << "RemoteID received: vendor=" << remoteID->getVendor() << ", length=" << remoteID->getVendorDataLen() << "." << LogEnd; msg->setRemoteID(remoteID); remoteID = 0; remoteID = msg->getRemoteID(); PrintHex("RemoteID:", (uint8_t*)remoteID->getVendorData(), remoteID->getVendorDataLen()); } return (Ptr*)msg; }