static RTEXITCODE handleOp(HandlerArg *a, OPCODE enmCode, int iStart, int *pcProcessed)
{
    if (a->argc - iStart < 2)
        return errorSyntax(USAGE_DHCPSERVER, "Not enough parameters");

    int index = iStart;
    HRESULT rc;
    bool fOptionsRead = false;
    bool fVmOptionRead = false;

    const char *pszVmName = NULL;
    const char *pNetName = NULL;
    const char *pIfName = NULL;
    const char * pIp = NULL;
    const char * pNetmask = NULL;
    const char * pLowerIp = NULL;
    const char * pUpperIp = NULL;

    uint8_t u8OptId = (uint8_t)~0;
    uint8_t u8Slot = (uint8_t)~0;

    int enable = -1;

    DhcpOpts        GlobalDhcpOptions;
    VmSlot2OptionsM VmSlot2Options;
    VmConfigs       VmConfigs2Delete;

    int c;
    RTGETOPTUNION ValueUnion;
    RTGETOPTSTATE GetState;
    RTGetOptInit(&GetState,
                 a->argc,
                 a->argv,
                 g_aDHCPIPOptions,
                 enmCode != OP_REMOVE ? RT_ELEMENTS(g_aDHCPIPOptions) : 4, /* we use only --netname and --ifname for remove*/
                 index,
                 RTGETOPTINIT_FLAGS_NO_STD_OPTS);
    while ((c = RTGetOpt(&GetState, &ValueUnion)))
    {
        switch (c)
        {
            case 't':   // --netname
                if(pNetName)
                    return errorSyntax(USAGE_DHCPSERVER, "You can only specify --netname once.");
                else if (pIfName)
                    return errorSyntax(USAGE_DHCPSERVER, "You can either use a --netname or --ifname for identifying the DHCP server.");
                else
                {
                    pNetName = ValueUnion.psz;
                }
            break;
            case 'f':   // --ifname
                if(pIfName)
                    return errorSyntax(USAGE_DHCPSERVER, "You can only specify --ifname once.");
                else if (pNetName)
                    return errorSyntax(USAGE_DHCPSERVER, "You can either use a --netname or --ipname for identifying the DHCP server.");
                else
                {
                    pIfName = ValueUnion.psz;
                }
            break;
            case 'a':   // -ip
                if(pIp)
                    return errorSyntax(USAGE_DHCPSERVER, "You can only specify --ip once.");
                else
                {
                    pIp = ValueUnion.psz;
                }
            break;
            case 'm':   // --netmask
                if(pNetmask)
                    return errorSyntax(USAGE_DHCPSERVER, "You can only specify --netmask once.");
                else
                {
                    pNetmask = ValueUnion.psz;
                }
            break;
            case 'l':   // --lowerip
                if(pLowerIp)
                    return errorSyntax(USAGE_DHCPSERVER, "You can only specify --lowerip once.");
                else
                {
                    pLowerIp = ValueUnion.psz;
                }
            break;
            case 'u':   // --upperip
                if(pUpperIp)
                    return errorSyntax(USAGE_DHCPSERVER, "You can only specify --upperip once.");
                else
                {
                    pUpperIp = ValueUnion.psz;
                }
            break;
            case 'e':   // --enable
                if(enable >= 0)
                    return errorSyntax(USAGE_DHCPSERVER, "You can specify either --enable or --disable once.");
                else
                {
                    enable = 1;
                }
            break;
            case 'd':   // --disable
                if(enable >= 0)
                    return errorSyntax(USAGE_DHCPSERVER, "You can specify either --enable or --disable once.");
                else
                {
                    enable = 0;
                }
            break;
            case VINF_GETOPT_NOT_OPTION:
                return errorSyntax(USAGE_DHCPSERVER, "unhandled parameter: %s", ValueUnion.psz);
            break;

            case 'o': // --options
                {
        // {"--vm",                'n', RTGETOPT_REQ_STRING}, /* only with -o */
        // {"--slot",              's', RTGETOPT_REQ_UINT8}, /* only with -o and -n*/
        // {"--id",                'i', RTGETOPT_REQ_UINT8}, /* only with -o */
        // {"--value",             'p', RTGETOPT_REQ_STRING} /* only with -i */
                    if (fOptionsRead)
                        return errorSyntax(USAGE_DHCPSERVER,
                                           "previos option edition  wasn't finished");
                    fOptionsRead = true;
                    fVmOptionRead = false; /* we want specify new global or vm option*/
                    u8Slot = (uint8_t)~0;
                    u8OptId = (uint8_t)~0;
                    pszVmName = NULL;
                } /* end of --options  */
                break;

            case 'n': // --vm-name
                {
                    if (fVmOptionRead)
                        return errorSyntax(USAGE_DHCPSERVER,
                                           "previous vm option edition wasn't finished");
                    else
                        fVmOptionRead = true;
                    u8Slot = (uint8_t)~0; /* clear slor */
                    pszVmName = RTStrDup(ValueUnion.psz);
                }
                break; /* end of --vm-name */

            case 's': // --slot
                {
                    if (!fVmOptionRead)
                        return errorSyntax(USAGE_DHCPSERVER,
                                           "vm name wasn't specified");

                    u8Slot = ValueUnion.u8;
                }
                break; /* end of --slot */

            case 'i': // --id
                {
                    if (!fOptionsRead)
                        return errorSyntax(USAGE_DHCPSERVER,
                                           "-o wasn't found");

                    u8OptId = ValueUnion.u8;
                }
                break; /* end of --id */

            case 'p': // --value
                {
                    if (!fOptionsRead)
                        return errorSyntax(USAGE_DHCPSERVER,
                                           "-o wasn't found");

                    if (u8OptId == (uint8_t)~0)
                        return errorSyntax(USAGE_DHCPSERVER,
                                           "--id wasn't found");
                    if (   fVmOptionRead
                        && u8Slot == (uint8_t)~0)
                        return errorSyntax(USAGE_DHCPSERVER,
                                           "--slot wasn't found");

                    DhcpOpts &opts = fVmOptionRead ? VmSlot2Options[VmNameSlotKey(pszVmName, u8Slot)]
                                                    : GlobalDhcpOptions;
                    std::string strVal = ValueUnion.psz;
                    opts.push_back(DhcpOptSpec((DhcpOpt_T)u8OptId, strVal));

                }
                break; // --end of value

            default:
                if (c > 0)
                {
                    if (RT_C_IS_GRAPH(c))
                        return errorSyntax(USAGE_DHCPSERVER, "unhandled option: -%c", c);
                    else
                        return errorSyntax(USAGE_DHCPSERVER, "unhandled option: %i", c);
                }
                else if (c == VERR_GETOPT_UNKNOWN_OPTION)
                    return errorSyntax(USAGE_DHCPSERVER, "unknown option: %s", ValueUnion.psz);
                else if (ValueUnion.pDef)
                    return errorSyntax(USAGE_DHCPSERVER, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
                else
                    return errorSyntax(USAGE_DHCPSERVER, "%Rrs", c);
        }
    }

    if(! pNetName && !pIfName)
        return errorSyntax(USAGE_DHCPSERVER, "You need to specify either --netname or --ifname to identify the DHCP server");

    if(   enmCode != OP_REMOVE
       && GlobalDhcpOptions.size() == 0
       && VmSlot2Options.size() == 0)
    {
        if(enable < 0 || pIp || pNetmask || pLowerIp || pUpperIp)
        {
            if(!pIp)
                return errorSyntax(USAGE_DHCPSERVER, "You need to specify --ip option");

            if(!pNetmask)
                return errorSyntax(USAGE_DHCPSERVER, "You need to specify --netmask option");

            if(!pLowerIp)
                return errorSyntax(USAGE_DHCPSERVER, "You need to specify --lowerip option");

            if(!pUpperIp)
                return errorSyntax(USAGE_DHCPSERVER, "You need to specify --upperip option");
        }
    }

    Bstr NetName;
    if(!pNetName)
    {
        ComPtr<IHost> host;
        CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));

        ComPtr<IHostNetworkInterface> hif;
        CHECK_ERROR(host, FindHostNetworkInterfaceByName(Bstr(pIfName).mutableRaw(), hif.asOutParam()));
        if (FAILED(rc))
            return errorArgument("Could not find interface '%s'", pIfName);

        CHECK_ERROR(hif, COMGETTER(NetworkName) (NetName.asOutParam()));
        if (FAILED(rc))
            return errorArgument("Could not get network name for the interface '%s'", pIfName);
    }
    else
    {
        NetName = Bstr(pNetName);
    }

    ComPtr<IDHCPServer> svr;
    rc = a->virtualBox->FindDHCPServerByNetworkName(NetName.mutableRaw(), svr.asOutParam());
    if(enmCode == OP_ADD)
    {
        if (SUCCEEDED(rc))
            return errorArgument("DHCP server already exists");

        CHECK_ERROR(a->virtualBox, CreateDHCPServer(NetName.mutableRaw(), svr.asOutParam()));
        if (FAILED(rc))
            return errorArgument("Failed to create the DHCP server");
    }
    else if (FAILED(rc))
    {
        return errorArgument("DHCP server does not exist");
    }

    if(enmCode != OP_REMOVE)
    {
        if (pIp || pNetmask || pLowerIp || pUpperIp)
        {
            CHECK_ERROR(svr, SetConfiguration (
                          Bstr(pIp).mutableRaw(),
                          Bstr(pNetmask).mutableRaw(),
                          Bstr(pLowerIp).mutableRaw(),
                          Bstr(pUpperIp).mutableRaw()));
            if(FAILED(rc))
                return errorArgument("Failed to set configuration");
        }

        if(enable >= 0)
        {
            CHECK_ERROR(svr, COMSETTER(Enabled) ((BOOL)enable));
        }

        /* option processing */
        DhcpOptIterator itOpt;
        VmSlot2OptionsIterator it;

        /* Global Options */
        for(itOpt = GlobalDhcpOptions.begin();
            itOpt != GlobalDhcpOptions.end();
            ++itOpt)
        {
            CHECK_ERROR(svr,
                        AddGlobalOption(
                          itOpt->first,
                          com::Bstr(itOpt->second.c_str()).raw()));
        }

        /* heh, vm slot options. */

        for (it = VmSlot2Options.begin();
             it != VmSlot2Options.end();
             ++it)
        {
            for(itOpt = it->second.begin();
                itOpt != it->second.end();
                ++itOpt)
            {
                CHECK_ERROR(svr,
                            AddVmSlotOption(Bstr(it->first.VmName.c_str()).raw(),
                                            it->first.u8Slot,
                                            itOpt->first,
                                            com::Bstr(itOpt->second.c_str()).raw()));
            }
        }
    }
    else
    {
        CHECK_ERROR(a->virtualBox, RemoveDHCPServer(svr));
        if(FAILED(rc))
            return errorArgument("Failed to remove server");
    }

    return RTEXITCODE_SUCCESS;
}
Exemple #2
0
static int handleOp(HandlerArg *a, OPCODE enmCode, int iStart, int *pcProcessed)
{
    if (a->argc - iStart < 2)
        return errorSyntax(USAGE_NATNETWORK, "Not enough parameters");

    int index = iStart;
    HRESULT rc;

    const char *pNetName = NULL;
    const char *pNetworkCidr = NULL;
    int enable = -1;
    int dhcp = -1;
    int ipv6 = -1;

    VPF2DELETE vPfName2Delete;
    VPF2ADD vPf2Add;

    int c;
    RTGETOPTUNION ValueUnion;
    RTGETOPTSTATE GetState;

    RTGetOptInit(&GetState,
                 a->argc,
                 a->argv,
                 g_aNATNetworkIPOptions,
                 enmCode != OP_REMOVE ? RT_ELEMENTS(g_aNATNetworkIPOptions) : 4, /* we use only --netname and --ifname for remove*/
                 index,
                 RTGETOPTINIT_FLAGS_NO_STD_OPTS);
    while ((c = RTGetOpt(&GetState, &ValueUnion)))
    {
        switch (c)
        {
            case 't':   // --netname
                if (pNetName)
                    return errorSyntax(USAGE_NATNETWORK, "You can only specify --netname once.");
                else
                {
                    pNetName = ValueUnion.psz;
                }
            break;

            case 'n':   // --network
                if (pNetworkCidr)
                    return errorSyntax(USAGE_NATNETWORK, "You can only specify --network once.");
                else
                {
                    pNetworkCidr = ValueUnion.psz;
                }
            break;

            case 'e':   // --enable
                if(enable >= 0)
                    return errorSyntax(USAGE_NATNETWORK, "You can specify either --enable or --disable once.");
                else
                {
                    enable = 1;
                }
            break;

            case 'd':   // --disable
                if (enable >= 0)
                    return errorSyntax(USAGE_NATNETWORK, "You can specify either --enable or --disable once.");
                else
                {
                    enable = 0;
                }
            break;
           
            case 'h':
                if (dhcp != -1)
                    return errorSyntax(USAGE_NATNETWORK, "You can specify --dhcp once.");
                dhcp = ValueUnion.f;
                break;

            case '6':
                if (ipv6 != -1)
                    return errorSyntax(USAGE_NATNETWORK, "You can specify --ipv6 once.");
                ipv6 = ValueUnion.f;
                break;

            case 'P': /* ipv6 portforwarding*/
            case 'p': /* ipv4 portforwarding */
            {
                if (RTStrCmp(ValueUnion.psz, "delete") != 0)
                {
                    PORTFORWARDRULE Pfr;

                    /* netPfStrToPf will clean up the Pfr */
                    int irc = netPfStrToPf(ValueUnion.psz, (c == 'P'), &Pfr);
                    if (RT_FAILURE(irc))
                        return errorSyntax(USAGE_NATNETWORK,
                                           "Invalid port-forward rule %s\n",
                                           ValueUnion.psz);
                    
                    vPf2Add.push_back(Pfr);
                }
                else
                {
                    int vrc;
                    RTGETOPTUNION NamePf2DeleteUnion;
                    PFNAME2DELETE Name2Delete;

                    if (enmCode != OP_MODIFY)
                        return errorSyntax(USAGE_NATNETWORK,
                                           "Port-forward could be deleted on modify \n");

                    vrc = RTGetOptFetchValue(&GetState, 
                                             &NamePf2DeleteUnion, 
                                             RTGETOPT_REQ_STRING);
                    if (RT_FAILURE(vrc))
                        return errorSyntax(USAGE_NATNETWORK,
                                           "Not enough parmaters\n");
                    
                    if (strlen(NamePf2DeleteUnion.psz) > PF_NAMELEN)
                        return errorSyntax(USAGE_NATNETWORK,
                                           "Port-forward rule name is too long\n");

                    RT_ZERO(Name2Delete);
                    RTStrCopy(Name2Delete.aszName, 
                              PF_NAMELEN, 
                              NamePf2DeleteUnion.psz);
                    Name2Delete.fIPv6 = (c == 'P');

                    vPfName2Delete.push_back(Name2Delete);
                }
                break;
            }

            case VINF_GETOPT_NOT_OPTION:
                return errorSyntax(USAGE_NATNETWORK, 
                                   "unhandled parameter: %s", 
                                   ValueUnion.psz);
            break;

            default:
                if (c > 0)
                {
                    if (RT_C_IS_GRAPH(c))
                        return errorSyntax(USAGE_NATNETWORK, 
                                           "unhandled option: -%c", c);
                    else
                        return errorSyntax(USAGE_NATNETWORK, 
                                           "unhandled option: %i", c);
                }
                else if (c == VERR_GETOPT_UNKNOWN_OPTION)
                    return errorSyntax(USAGE_NATNETWORK, 
                                       "unknown option: %s", ValueUnion.psz);
                else if (ValueUnion.pDef)
                    return errorSyntax(USAGE_NATNETWORK, 
                                       "%s: %Rrs", ValueUnion.pDef->pszLong, c);
                else
                    return errorSyntax(USAGE_NATNETWORK, "%Rrs", c);
        }
    }

    if (!pNetName)
        return errorSyntax(USAGE_NATNETWORK, 
                           "You need to specify --netname option");
    /* verification */
    switch (enmCode)
    {
        case OP_ADD:
            if (!pNetworkCidr)
                return errorSyntax(USAGE_NATNETWORK, 
                                   "You need to specify --network option");
            break;
        case OP_MODIFY:
        case OP_REMOVE:
        case OP_START:
        case OP_STOP:
            break;
        default:
            AssertMsgFailedReturn(("Unknown operation (:%d)", enmCode), VERR_NOT_IMPLEMENTED);
    }

    Bstr NetName;
    NetName = Bstr(pNetName);
    

    ComPtr<INATNetwork> net;
    rc = a->virtualBox->FindNATNetworkByName(NetName.mutableRaw(), net.asOutParam());
    if(enmCode == OP_ADD)
    {
        if (SUCCEEDED(rc))
            return errorArgument("NATNetwork server already exists");

        CHECK_ERROR(a->virtualBox, CreateNATNetwork(NetName.raw(), net.asOutParam()));
        if (FAILED(rc))
            return errorArgument("Failed to create the NAT network service");
    }
    else if (FAILED(rc))
    {
        return errorArgument("NATNetwork server does not exist");
    }

    switch (enmCode)
    {
    case OP_ADD:
    case OP_MODIFY:
    {
        if (pNetworkCidr)
        {
            CHECK_ERROR(net, COMSETTER(Network)(Bstr(pNetworkCidr).raw()));
            if(FAILED(rc))
              return errorArgument("Failed to set configuration");
        }
        if (dhcp >= 0)
        {
              CHECK_ERROR(net, COMSETTER(NeedDhcpServer) ((BOOL)dhcp));
              if(FAILED(rc))
                return errorArgument("Failed to set configuration");
        }
        
        if (ipv6 >= 0)
        {
              CHECK_ERROR(net, COMSETTER(IPv6Enabled) ((BOOL)ipv6));
              if(FAILED(rc))
                return errorArgument("Failed to set configuration");
        }
        
        if (!vPfName2Delete.empty())
        {
            VPF2DELETEITERATOR it;
            for (it = vPfName2Delete.begin(); it != vPfName2Delete.end(); ++it)
            {
                CHECK_ERROR(net, RemovePortForwardRule((BOOL)(*it).fIPv6,
                                                       Bstr((*it).aszName).raw()));
                if(FAILED(rc))
                    return errorArgument("Failed to delete pf");

            }
        }

        if (!vPf2Add.empty())
        {
            VPF2ADDITERATOR it;
            for(it = vPf2Add.begin(); it != vPf2Add.end(); ++it)
            {
                NATProtocol_T proto = NATProtocol_TCP;
                if ((*it).iPfrProto == IPPROTO_TCP)
                    proto = NATProtocol_TCP;
                else if ((*it).iPfrProto == IPPROTO_UDP)
                    proto = NATProtocol_UDP;
                else
                    continue; /* XXX: warning here. */

                CHECK_ERROR(net, AddPortForwardRule(
                              (BOOL)(*it).fPfrIPv6,
                              Bstr((*it).aszPfrName).raw(),
                              proto,
                              Bstr((*it).aszPfrHostAddr).raw(),
                              (*it).u16PfrHostPort,
                              Bstr((*it).aszPfrGuestAddr).raw(),
                              (*it).u16PfrGuestPort));
                if(FAILED(rc))
                    return errorArgument("Failed to add pf");

            }
        }
        
        if(enable >= 0)
        {
            CHECK_ERROR(net, COMSETTER(Enabled) ((BOOL)enable));
            if(FAILED(rc))
              return errorArgument("Failed to set configuration");

        }
        break;
    }
    case OP_REMOVE:
    {
        CHECK_ERROR(a->virtualBox, RemoveNATNetwork(net));
        if(FAILED(rc))
          return errorArgument("Failed to remove nat network");
        break;
    }
    case OP_START:
    {
        CHECK_ERROR(net, Start(Bstr("whatever").raw()));
        if(FAILED(rc))
          return errorArgument("Failed to start network");
        break;
    }
    case OP_STOP:
    {
        CHECK_ERROR(net, Stop());
        if(FAILED(rc))
          return errorArgument("Failed to start network");
        break;
    }
    default:;
    }
    return 0;
}