Exemplo n.º 1
0
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;
 }
Exemplo n.º 2
0
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;
 }