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; }
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; }