Merge with Ipv6 contribution

This commit is contained in:
Feodor 2012-08-20 12:35:46 -07:00
commit df5da7b015
35 changed files with 2893 additions and 158 deletions

BIN
IPv6 Test Cases.docx Normal file

Binary file not shown.

View file

@ -0,0 +1,164 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace WebsitePanel.EnterpriseServer {
public struct IPAddress {
public Int128 Address;
public bool V6 { get; private set; }
public bool V4 { get { return !V6 || Null; } }
public bool IsSubnet { get; private set; }
public bool IsMask { get; private set; }
public int Cidr { get; private set; }
public bool Null { get; private set; }
public IPAddress LastSubnetIP { get { return new IPAddress { Address = (Address | (~((Int128)0) >> (V4 ? Cidr + 64 : Cidr))), Cidr = V4 ? 32 : 128, IsSubnet = false, Null = false, V6 = V6 }; } }
public IPAddress FirstSubnetIP { get { return new IPAddress { Address = (Address & ~(~((Int128)0) >> (V4 ? Cidr + 64 : Cidr))) + 1, Cidr = V4 ? 32 : 128, IsSubnet = false, Null = false, V6 = V6 }; } }
public Int128 Mask { get { return IsSubnet ? Int128.MinValue >> (Cidr-1) : Address; } }
const int c = 256*256;
public static IPAddress Parse(string ip)
{
IPAddress adr = default(IPAddress);
adr.V6 = false;
if (String.IsNullOrEmpty(ip)) {
adr.Address = 0; adr.Null = true; adr.Cidr = 32; adr.IsSubnet = false;
return adr;
}
if (ip.Contains('/')) {
var tokens = ip.Split('/');
ip = tokens[0];
adr.IsSubnet = true;
adr.Cidr = Utils.ParseInt(tokens[1], -1);
}
if (string.IsNullOrWhiteSpace(ip)) {
adr.IsMask = true; adr.V6 = true;
adr.Address = adr.Mask;
} else {
var ipadr = System.Net.IPAddress.Parse(ip);
if (adr.V6 = ipadr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6) {
byte[] bytes = ipadr.GetAddressBytes();
Int128 a = 0;
for (int i = 0; i < 16; i++) {
a = a * 256 + bytes[i];
}
adr.Address = a;
} else {
string[] parts = ip.Split('.');
adr.Address = (Int128)(Int32.Parse(parts[3]) +
(Int32.Parse(parts[2]) << 8) +
(Int32.Parse(parts[1]) << 16) +
(Int32.Parse(parts[0]) << 24));
}
}
if (adr.V4 && (adr.Cidr > 32 || 0 > adr.Cidr)) throw new ArgumentOutOfRangeException("Cidr must not be greater than 32 for IPv4 Addresses.");
if (adr.V6 && (adr.Cidr > 128 || 0 > adr.Cidr)) throw new ArgumentOutOfRangeException("Cidr must not be greater than 128 for IPv6 Addresses.");
return adr;
}
public override string ToString()
{
if (Null)
return "";
var s = new System.Text.StringBuilder();
if (!V6) {
var ipl = (long)Address;
s.Append(String.Format("{0}.{1}.{2}.{3}", (ipl >> 24) & 0xFFL, (ipl >> 16) & 0xFFL, (ipl >> 8) & 0xFFL, (ipl & 0xFFL)));
} else if (!IsMask) {
var vals = new List<int>();
int i;
Int128 a = Address;
for (i = 0; i < 8; i++) {
vals.Add((int)(a % c));
a = a / c;
}
int index = -1, n = 0, m = 0;
for (i = 7; i >= 0; i--) {
if (vals[i] == 0) {
n++;
if (n > m) {
index = i;
m = n;
}
}
}
index += m-1;
i = 7;
while (i >= 0) {
if (i == index) {
if (m == 8) s.Append("::");
else s.Append(":");
i -= m;
}
if (i >= 0) {
if (i < 7) s.Append(":");
s.Append(vals[i].ToString("x"));
}
i--;
}
}
if (IsSubnet && !(IsMask && V4)) {
s.Append('/'); s.Append(Cidr.ToString());
}
return s.ToString();
}
public string ToV4MaskString() {
V6 = false;
IsMask = true;
return ToString();
}
public static bool operator ==(IPAddress a, IPAddress b) { return a.Address == b.Address && a.Null == b.Null && (a.Null || !(a.IsSubnet && b.IsSubnet || a.IsMask && b.IsMask) || a.Cidr == b.Cidr); }
public static bool operator ==(IPAddress a, long b) { return a.Address == b; }
public static bool operator !=(IPAddress a, IPAddress b) { return !(a == b); }
public static bool operator !=(IPAddress a, long b) { return a.Address != b; }
public static bool operator <(IPAddress a, IPAddress b) { return a.Address < b.Address; }
public static bool operator >(IPAddress a, IPAddress b) { return a.Address > b.Address; }
public static bool operator <=(IPAddress a, IPAddress b) { return a.Address <= b.Address; }
public static bool operator >=(IPAddress a, IPAddress b) { return a.Address >= b.Address; }
/*
public static IPAddress operator +(IPAddress a, IPAddress b) {
if (a.IsSubnet || b.IsSubnet || a.V6 != b.V6) throw new ArgumentException("Arithmetic with subnets or mixed v4 & v6 addresses not supported.");
return new IPAddress { Address = a.Address + b.Address, Null = a.Null && b.Null, Cidr = 0, V6 = a.V6 };
}*/
public static Int128 operator -(IPAddress a, IPAddress b) {
if (a.IsSubnet || b.IsSubnet || a.V6 != b.V6) throw new ArgumentException("Arithmetic with subnets or mixed v4 & v6 addresses not supported.");
return a.Address - b.Address;
}
public static IPAddress operator +(IPAddress a, Int128 b) {
return new IPAddress { Address = a.Address + b, Null = a.Null, Cidr = a.V4 ? 32 : 128, V6 = a.V6 };
}
public static IPAddress operator -(IPAddress a, Int128 b) {
return new IPAddress { Address = a.Address - b, Null = a.Null, Cidr = a.V4 ? 32 : 128, V6 = a.V6 };
}
public static IPAddress operator |(IPAddress a, IPAddress b) {
if (a.V6 != b.V6) throw new ArgumentException("Arithmetic with mixed v4 & v6 addresses not supported.");
return new IPAddress { Address = a.Address | b.Address, Cidr = a.V4 ? 32 : 128, Null = false, V6 = a.V6, IsSubnet = false };
}
public static IPAddress operator &(IPAddress a, IPAddress b) {
if (a.V6 != b.V6) throw new ArgumentException("Arithmetic with mixed v4 & v6 addresses not supported.");
return new IPAddress { Address = a.Address | b.Address, Cidr = a.V4 ? 32 : 128, Null = false, V6 = a.V6, IsSubnet = false };
}
public static IPAddress operator ~(IPAddress a) {
if (a.Null) return new IPAddress { Address = 0, Null = true, Cidr = a.V4 ? 32 : 128, V6 = true, IsSubnet = false };
return new IPAddress { Address = ~a.Address, Cidr = a.Cidr , Null = false, V6 = a.V6, IsSubnet = false };
}
public static implicit operator IPAddress(NullIPAddress a) { return new IPAddress { Null = true, Address = 0, Cidr = -1 }; }
}
public class NullIPAddress { }
}

File diff suppressed because it is too large Load diff

View file

@ -281,7 +281,7 @@ namespace WebsitePanel.EnterpriseServer
rr.RecordType = (DnsRecordType)Enum.Parse(typeof(DnsRecordType), record.RecordType, true);
rr.RecordName = record.RecordName;
if (record.RecordType == "A")
if (record.RecordType == "A" || record.RecordType == "AAAA")
{
rr.RecordData = String.IsNullOrEmpty(record.RecordData) ? record.ExternalIP : record.RecordData;
rr.RecordData = Utils.ReplaceStringVariable(rr.RecordData, "ip", record.ExternalIP);

View file

@ -65,7 +65,7 @@ namespace WebsitePanel.EnterpriseServer
DnsRecord[] records = ServerController.GetDnsZoneRecords(domainId);
foreach (DnsRecord record in records)
{
if ((record.RecordType == DnsRecordType.A) && (String.Compare(recordName, record.RecordName, true) == 0))
if ((record.RecordType == DnsRecordType.A || record.RecordType == DnsRecordType.AAAA) && (String.Compare(recordName, record.RecordName, true) == 0))
{
CompleteTask(ret, CrmErrorCodes.CANNOT_CREATE_DNS_ZONE, null,
string.Format("DNS record already exists. DomainId={0}, RecordName={1}", domainId, recordName));
@ -73,8 +73,8 @@ namespace WebsitePanel.EnterpriseServer
return ret;
}
}
int res = ServerController.AddDnsZoneRecord(domainId, recordName, DnsRecordType.A, ip, 0, 0, 0, 0);
var type = ip.Contains(":") ? DnsRecordType.AAAA : DnsRecordType.A;
int res = ServerController.AddDnsZoneRecord(domainId, recordName, type, ip, 0);
if (res != 0)
{
CompleteTask(ret, CrmErrorCodes.CANNOT_CREATE_DNS_ZONE, null,
@ -373,7 +373,8 @@ namespace WebsitePanel.EnterpriseServer
try
{
int res = ServerController.DeleteDnsZoneRecord(domainId, recordName, DnsRecordType.A, ip);
var type = ip.Contains(":") ? DnsRecordType.AAAA : DnsRecordType.A;
int res = ServerController.DeleteDnsZoneRecord(domainId, recordName, type, ip);
if (res != 0)
{

View file

@ -948,6 +948,8 @@ namespace WebsitePanel.EnterpriseServer
public static ResultObject AddIPAddressesRange(IPAddressPool pool, int serverId,
string externalIP, string endIP, string internalIP, string subnetMask, string defaultGateway, string comments)
{
const int MaxSubnet = 512; // TODO bigger max subnet?
ResultObject res = new ResultObject();
#region Check account statuses
@ -973,23 +975,28 @@ namespace WebsitePanel.EnterpriseServer
return res;
}
long startExternalIP = ConvertIPToLong(externalIP);
long startInternalIP = ConvertIPToLong(internalIP);
long endExternalIP = ConvertIPToLong(endIP);
var startExternalIP = IPAddress.Parse(externalIP);
var startInternalIP = IPAddress.Parse(internalIP);
var endExternalIP = IPAddress.Parse(endIP);
// handle CIDR notation IP/Subnet addresses
if (startExternalIP.IsSubnet && endExternalIP == null) {
endExternalIP = startExternalIP.LastSubnetIP;
startExternalIP = startExternalIP.FirstSubnetIP;
}
if (startExternalIP.V6 != startInternalIP.V6 && (startExternalIP.V6 != endExternalIP.V6 && endExternalIP != null)) throw new NotSupportedException("All IP addresses must be either V4 or V6.");
int i = 0;
long step = (endExternalIP < startExternalIP) ? -1 : 1;
while (true)
{
if (i > 128)
if (i > MaxSubnet)
break;
// add IP address
DataProvider.AddIPAddress((int)pool, serverId,
ConvertLongToIP(startExternalIP),
ConvertLongToIP(startInternalIP),
subnetMask, defaultGateway, comments);
DataProvider.AddIPAddress((int)pool, serverId, startExternalIP.ToString(), startInternalIP.ToString(), subnetMask, defaultGateway, comments);
if (startExternalIP == endExternalIP)
break;
@ -2439,26 +2446,78 @@ namespace WebsitePanel.EnterpriseServer
#endregion
#region Private methods
public static long ConvertIPToLong(string ip)
/*
const int c = 256*256;
public static BigInt ConvertIPToInt(string ip, out bool v6)
{
v6 = false;
if (String.IsNullOrEmpty(ip))
return 0;
var adr = System.Net.IPAddress.Parse(ip);
if (v6 = adr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) {
string[] parts = ip.Split('.');
return Int32.Parse(parts[3]) +
return (BigInt)(Int32.Parse(parts[3]) +
(Int32.Parse(parts[2]) << 8) +
(Int32.Parse(parts[1]) << 16) +
(Int32.Parse(parts[0]) << 24);
(Int32.Parse(parts[0]) << 24));
} else {
byte[] bytes = adr.GetAddressBytes();
var a = BigInt.Zero;
for (int i = 0; i < 16; i--) {
a = a*256 + bytes[i];
}
return a;
}
}
public static string ConvertLongToIP(long ip)
public static string ConvertIntToIP(BigInt ip, bool v6)
{
if (ip == 0)
if (ip == BigInt.Zero)
return "";
if (!v6) {
var ipl = (long)ip;
return String.Format("{0}.{1}.{2}.{3}",
(ip >> 24) & 0xFFL, (ip >> 16) & 0xFFL, (ip >> 8) & 0xFFL, (ip & 0xFFL));
(ipl >> 24) & 0xFFL, (ipl >> 16) & 0xFFL, (ipl >> 8) & 0xFFL, (ipl & 0xFFL));
} else {
var vals = new List<int>();
int i;
for (i = 0; i < 8; i++) {
vals.Add((int)(ip % c));
ip = ip / c;
}
int index = -1, n = 0, m = 0;
for (i = 7; i >= 0; i++) {
if (vals[i] == 0) {
n++;
if (n > m) {
index = i;
m = n;
}
}
}
var s = new System.Text.StringBuilder();
i = 7;
while (i >= 0) {
if (i != index) {
if (i < 7) s.Append(":");
s.Append(vals[i].ToString("x"));
i--;
} else {
s.Append(":");
while (vals[i] == 0) i--;
}
}
return s.ToString();
}
}
*/
#endregion
}
}

View file

@ -339,14 +339,19 @@ namespace WebsitePanel.EnterpriseServer.Code.SharePoint
DnsRecord[] records = ServerController.GetDnsZoneRecords(domain.DomainId);
foreach (DnsRecord record in records)
{
if (record.RecordType.Equals(DnsRecordType.A) && (record.RecordName == hostName))
var type = record.RecordType;
if ((type == DnsRecordType.A || type == DnsRecordType.AAAA) && String.IsNullOrEmpty(record.RecordName))
{
ServerController.DeleteDnsZoneRecord(domain.DomainId, hostName, DnsRecordType.A, record.RecordData);
ServerController.DeleteDnsZoneRecord(domain.DomainId, String.Empty, type, record.RecordData);
break;
}
}
ServerController.AddDnsZoneRecord(domain.DomainId, hostName, DnsRecordType.A, hostedSharePointSettings["RootWebApplicationIpAddress"], 0, 0, 0, 0);
var ip = hostedSharePointSettings["RootWebApplicationIpAddress"];
var type2 = ip.Contains(":") ? DnsRecordType.AAAA : DnsRecordType.A;
ServerController.AddDnsZoneRecord(domain.DomainId, String.Empty, type2, ip, 0);
}
}
@ -411,7 +416,26 @@ namespace WebsitePanel.EnterpriseServer.Code.SharePoint
DomainInfo domain = ServerController.GetDomain(domainName);
if (domain != null)
{
ServerController.DeleteDnsZoneRecord(domain.DomainId, hostName, DnsRecordType.A, hostedSharePointSettings["RootWebApplicationIpAddress"]);
var ip = hostedSharePointSettings["RootWebApplicationIpAddress"];
var type = ip.Contains(":") ? DnsRecordType.AAAA : DnsRecordType.A;
ServerController.DeleteDnsZoneRecord(domain.DomainId, String.Empty, type, ip);
ServerController.DeleteDnsZoneRecord(domain.DomainId, "www", type, ip);
if (!String.IsNullOrEmpty(domain.WebSiteName))
{
DnsRecord[] records = ServerController.GetDnsZoneRecords(domain.DomainId);
foreach (DnsRecord record in records)
{
type = record.RecordType;
if ((type == DnsRecordType.A || type == DnsRecordType.AAAA) && record.RecordName.Equals("www", StringComparison.CurrentCultureIgnoreCase))
{
ServerController.AddDnsZoneRecord(domain.DomainId, String.Empty, DnsRecordType.A,
record.RecordData, 0);
break;
}
}
}
}
}

View file

@ -2969,14 +2969,16 @@ namespace WebsitePanel.EnterpriseServer
{
// custom format
nic.NetworkFormat = settings["PrivateIPAddress"];
nic.SubnetMask = GetPrivateNetworkSubnetMask(settings["PrivateSubnetMask"]);
var v6 = IPAddress.Parse(nic.NetworkFormat).V6;
nic.SubnetMask = GetPrivateNetworkSubnetMask(settings["PrivateSubnetMask"], v6);
}
else
{
// standard format
string[] formatPair = settings["PrivateNetworkFormat"].Split('/');
nic.NetworkFormat = formatPair[0];
nic.SubnetMask = GetPrivateNetworkSubnetMask(formatPair[1]);
var v6 = IPAddress.Parse(nic.NetworkFormat).V6;
nic.SubnetMask = GetPrivateNetworkSubnetMask(formatPair[1], v6);
}
nic.SubnetMaskCidr = GetSubnetMaskCidr(nic.SubnetMask);
@ -3038,7 +3040,7 @@ namespace WebsitePanel.EnterpriseServer
List<PrivateIPAddress> ips = GetPackagePrivateIPAddresses(vm.PackageId);
// sort them
SortedList<long, string> sortedIps = GetSortedNormalizedIPAddresses(ips, nic.SubnetMask);
SortedList<IPAddress, string> sortedIps = GetSortedNormalizedIPAddresses(ips, nic.SubnetMask);
if (selectRandom)
{
@ -3209,14 +3211,14 @@ namespace WebsitePanel.EnterpriseServer
return res;
}
private static string GenerateNextAvailablePrivateIP(SortedList<long, string> ips, string subnetMask, string startIPAddress)
private static string GenerateNextAvailablePrivateIP(SortedList<IPAddress, string> ips, string subnetMask, string startIPAddress)
{
// start IP address
long startIp = ServerController.ConvertIPToLong(startIPAddress);
long mask = ServerController.ConvertIPToLong(subnetMask);
var startIp = IPAddress.Parse(startIPAddress);
var mask = IPAddress.Parse(subnetMask);
long lastAddress = (startIp & ~mask) - 1;
foreach (long addr in ips.Keys)
var lastAddress = (startIp & ~mask) - 1;
foreach (var addr in ips.Keys)
{
if ((addr - lastAddress) > 1)
{
@ -3229,11 +3231,11 @@ namespace WebsitePanel.EnterpriseServer
}
}
long genAddr = lastAddress + 1;
var genAddr = lastAddress + 1;
// convert to IP address
long ip = startIp & mask | (uint)genAddr;
string genIP = ServerController.ConvertLongToIP(ip);
var ip = startIp & mask | genAddr;
string genIP = ip.ToString();
// store in cache
ips.Add(genAddr, genIP);
@ -3241,46 +3243,44 @@ namespace WebsitePanel.EnterpriseServer
return genIP;
}
private static SortedList<long, string> GetSortedNormalizedIPAddresses(List<PrivateIPAddress> ips, string subnetMask)
private static SortedList<IPAddress, string> GetSortedNormalizedIPAddresses(List<PrivateIPAddress> ips, string subnetMask)
{
long mask = ServerController.ConvertIPToLong(subnetMask);
SortedList<long, string> sortedIps = new SortedList<long, string>();
var mask = IPAddress.Parse(subnetMask);
SortedList<IPAddress, string> sortedIps = new SortedList<IPAddress, string>();
foreach (PrivateIPAddress ip in ips)
{
long addr = ~mask & ServerController.ConvertIPToLong(ip.IPAddress);
var addr = ~mask & IPAddress.Parse(ip.IPAddress);
sortedIps.Add(addr, ip.IPAddress);
}
return sortedIps;
}
private static string GetPrivateNetworkSubnetMask(string cidr)
{
int digits = 32 - Utils.ParseInt(cidr, 0);
long mask = 0xFFFFFFFF;
mask = mask << digits;
return ServerController.ConvertLongToIP(mask);
private static string GetPrivateNetworkSubnetMask(string cidr, bool v6) {
if (v6) return "/" + cidr;
else return IPAddress.Parse("/" + cidr).ToV4MaskString();
}
private static string GetSubnetMaskCidr(string subnetMask)
{
private static string GetSubnetMaskCidr(string subnetMask) {
if (String.IsNullOrEmpty(subnetMask))
return subnetMask;
var ip = IPAddress.Parse(subnetMask);
if (ip.V4) {
int cidr = 32;
long mask = ServerController.ConvertIPToLong(subnetMask);
while ((mask & 1) == 0 && cidr > 0)
{
long mask = (long)ip.Address;
while ((mask & 1) == 0 && cidr > 0) {
mask >>= 1;
cidr -= 1;
}
return cidr.ToString();
} else {
return ip.Cidr.ToString();
}
}
private static bool CheckPrivateIPAddress(string subnetMask, string ipAddress)
{
long mask = ServerController.ConvertIPToLong(subnetMask);
long ip = ServerController.ConvertIPToLong(ipAddress);
var mask = IPAddress.Parse(subnetMask);
var ip = IPAddress.Parse(ipAddress);
return ((mask & ip) == mask);
}

View file

@ -3019,14 +3019,16 @@ namespace WebsitePanel.EnterpriseServer
{
// custom format
nic.NetworkFormat = settings["PrivateIPAddress"];
nic.SubnetMask = GetPrivateNetworkSubnetMask(settings["PrivateSubnetMask"]);
var v6 = IPAddress.Parse(nic.NetworkFormat).V6;
nic.SubnetMask = GetPrivateNetworkSubnetMask(settings["PrivateSubnetMask"], v6);
}
else
{
// standard format
string[] formatPair = settings["PrivateNetworkFormat"].Split('/');
nic.NetworkFormat = formatPair[0];
nic.SubnetMask = GetPrivateNetworkSubnetMask(formatPair[1]);
var v6 = IPAddress.Parse(nic.NetworkFormat).V6;
nic.SubnetMask = GetPrivateNetworkSubnetMask(formatPair[1], v6);
}
nic.SubnetMaskCidr = GetSubnetMaskCidr(nic.SubnetMask);
@ -3088,7 +3090,7 @@ namespace WebsitePanel.EnterpriseServer
List<PrivateIPAddress> ips = GetPackagePrivateIPAddresses(vm.PackageId);
// sort them
SortedList<long, string> sortedIps = GetSortedNormalizedIPAddresses(ips, nic.SubnetMask);
SortedList<IPAddress, string> sortedIps = GetSortedNormalizedIPAddresses(ips, nic.SubnetMask);
if (selectRandom)
{
@ -3259,14 +3261,14 @@ namespace WebsitePanel.EnterpriseServer
return res;
}
private static string GenerateNextAvailablePrivateIP(SortedList<long, string> ips, string subnetMask, string startIPAddress)
private static string GenerateNextAvailablePrivateIP(SortedList<IPAddress, string> ips, string subnetMask, string startIPAddress)
{
// start IP address
long startIp = ServerController.ConvertIPToLong(startIPAddress);
long mask = ServerController.ConvertIPToLong(subnetMask);
var startIp = IPAddress.Parse(startIPAddress);
var mask = IPAddress.Parse(subnetMask);
long lastAddress = (startIp & ~mask) - 1;
foreach (long addr in ips.Keys)
var lastAddress = (startIp & ~mask) - 1;
foreach (var addr in ips.Keys)
{
if ((addr - lastAddress) > 1)
{
@ -3279,11 +3281,11 @@ namespace WebsitePanel.EnterpriseServer
}
}
long genAddr = lastAddress + 1;
var genAddr = lastAddress + 1;
// convert to IP address
long ip = startIp & mask | (uint)genAddr;
string genIP = ServerController.ConvertLongToIP(ip);
var ip = startIp & mask | genAddr;
string genIP = ip.ToString();
// store in cache
ips.Add(genAddr, genIP);
@ -3291,46 +3293,45 @@ namespace WebsitePanel.EnterpriseServer
return genIP;
}
private static SortedList<long, string> GetSortedNormalizedIPAddresses(List<PrivateIPAddress> ips, string subnetMask)
private static SortedList<IPAddress, string> GetSortedNormalizedIPAddresses(List<PrivateIPAddress> ips, string subnetMask)
{
long mask = ServerController.ConvertIPToLong(subnetMask);
SortedList<long, string> sortedIps = new SortedList<long, string>();
var mask = IPAddress.Parse(subnetMask);
SortedList<IPAddress, string> sortedIps = new SortedList<IPAddress, string>();
foreach (PrivateIPAddress ip in ips)
{
long addr = ~mask & ServerController.ConvertIPToLong(ip.IPAddress);
var addr = ~mask & IPAddress.Parse(ip.IPAddress);
sortedIps.Add(addr, ip.IPAddress);
}
return sortedIps;
}
private static string GetPrivateNetworkSubnetMask(string cidr)
private static string GetPrivateNetworkSubnetMask(string cidr, bool v6)
{
int digits = 32 - Utils.ParseInt(cidr, 0);
long mask = 0xFFFFFFFF;
mask = mask << digits;
return ServerController.ConvertLongToIP(mask);
if (v6) return "/" + cidr;
else return IPAddress.Parse("/" + cidr).ToV4MaskString();
}
private static string GetSubnetMaskCidr(string subnetMask)
{
private static string GetSubnetMaskCidr(string subnetMask) {
if (String.IsNullOrEmpty(subnetMask))
return subnetMask;
var ip = IPAddress.Parse(subnetMask);
if (ip.V4) {
int cidr = 32;
long mask = ServerController.ConvertIPToLong(subnetMask);
while ((mask & 1) == 0 && cidr > 0)
{
long mask = (long)ip.Address;
while ((mask & 1) == 0 && cidr > 0) {
mask >>= 1;
cidr -= 1;
}
return cidr.ToString();
} else {
return ip.Cidr.ToString();
}
}
private static bool CheckPrivateIPAddress(string subnetMask, string ipAddress)
{
long mask = ServerController.ConvertIPToLong(subnetMask);
long ip = ServerController.ConvertIPToLong(ipAddress);
var mask = IPAddress.Parse(subnetMask);
var ip = IPAddress.Parse(ipAddress);
return ((mask & ip) == mask);
}

View file

@ -603,11 +603,12 @@ namespace WebsitePanel.EnterpriseServer
private static void FillWebServerBindings(List<ServerBinding> bindings, List<GlobalDnsRecord> dnsRecords,
string ipAddr, string domainName)
// TODO test if IPv6 works
{
int bindingsCount = bindings.Count;
foreach (GlobalDnsRecord dnsRecord in dnsRecords)
{
if (dnsRecord.RecordType == "A" &&
if ((dnsRecord.RecordType == "A" || dnsRecord.RecordType == "AAAA") &&
dnsRecord.RecordName != "*")
{
string recordData = dnsRecord.RecordName +

View file

@ -18,7 +18,7 @@
</UpgradeBackupLocation>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile />
<UseIISExpress>false</UseIISExpress>
<UseIISExpress>true</UseIISExpress>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -124,6 +124,8 @@
<Compile Include="Code\Common\FileUtils.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Code\Common\Int128.cs" />
<Compile Include="Code\Common\IPAddress.cs" />
<Compile Include="Code\Common\MailHelper.cs" />
<Compile Include="Code\Common\ObjectUtils.cs" />
<Compile Include="Code\Common\SecurityContext.cs" />
@ -424,12 +426,11 @@
<VisualStudio>
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
<WebProjectProperties>
<UseIIS>False</UseIIS>
<UseIIS>True</UseIIS>
<AutoAssignPort>False</AutoAssignPort>
<DevelopmentServerPort>9005</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>
</IISUrl>
<IISUrl>http://localhost:9005/</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>

View file

@ -35,6 +35,7 @@ namespace WebsitePanel.Providers.DNS
public enum DnsRecordType
{
A,
AAAA,
NS,
MX,
CNAME,

View file

@ -267,6 +267,8 @@ namespace WebsitePanel.Providers.DNS
{
if (record.RecordType == DnsRecordType.A)
AddARecord(zoneName, record.RecordName, record.RecordData);
else if (record.RecordType == DnsRecordType.AAAA)
AddAAAARecord(zoneName, record.RecordName, record.RecordData);
else if (record.RecordType == DnsRecordType.CNAME)
AddCNameRecord(zoneName, record.RecordName, record.RecordData);
else if (record.RecordType == DnsRecordType.MX)
@ -293,7 +295,7 @@ namespace WebsitePanel.Providers.DNS
{
try
{
if (record.RecordType == DnsRecordType.A || record.RecordType == DnsRecordType.CNAME)
if (record.RecordType == DnsRecordType.A || record.RecordType == DnsRecordType.AAAA || record.RecordType == DnsRecordType.CNAME)
record.RecordName = CorrectRecordName(zoneName, record.RecordName);
// delete record
@ -377,6 +379,36 @@ namespace WebsitePanel.Providers.DNS
#endregion
#region AAAA records
private void AddAAAARecord(string zoneName, string host, string ip) {
// get all zone records
List<DnsRecord> records = GetZoneRecordsArrayList(zoneName);
// delete A record
//DeleteARecordInternal(records, zoneName, host);
//check if user tries to add existent zone record
foreach (DnsRecord dnsRecord in records) {
if ((String.Compare(dnsRecord.RecordName, host, StringComparison.OrdinalIgnoreCase) == 0)
&& (String.Compare(dnsRecord.RecordData, ip, StringComparison.OrdinalIgnoreCase) == 0)
)
return;
}
// add new A record
DnsRecord record = new DnsRecord();
record.RecordType = DnsRecordType.AAAA;
record.RecordName = host;
record.RecordData = ip;
records.Add(record);
// update zone
UpdateZone(zoneName, records);
}
#endregion
#region NS records
private void AddNsRecord(string zoneName, string host, string nameServer)
{
@ -630,6 +662,15 @@ namespace WebsitePanel.Providers.DNS
r.RecordText = zfLine;
records.Add(r);
}
else if (recordType == "AAAA") // A record
{
DnsRecord r = new DnsRecord();
r.RecordType = DnsRecordType.AAAA;
r.RecordName = CorrectRecordName(zoneName, recordName);
r.RecordData = recordData;
r.RecordText = zfLine;
records.Add(r);
}
else if (recordType == "CNAME") // CNAME record
{
DnsRecord r = new DnsRecord();
@ -728,6 +769,12 @@ namespace WebsitePanel.Providers.DNS
host = rr.RecordName;
data = rr.RecordData;
}
else if (rr.RecordType == DnsRecordType.AAAA)
{
type = "AAAA";
host = rr.RecordName;
data = rr.RecordData;
}
else if (rr.RecordType == DnsRecordType.NS)
{
type = "NS";

View file

@ -130,6 +130,8 @@ namespace WebsitePanel.Providers.DNS
ManagementObjectCollection rrsA = wmi.GetWmiObjects("MicrosoftDNS_AType", "DomainName='{0}'", zoneName);
ManagementObjectCollection rrsAAAA = wmi.GetWmiObjects("MicrosoftDNS_AAAAType", "DomainName='{0}'", zoneName);
ManagementObjectCollection rrsCNAME = wmi.GetWmiObjects("MicrosoftDNS_CNAMEType", "DomainName='{0}'", zoneName);
ManagementObjectCollection rrsMX = wmi.GetWmiObjects("MicrosoftDNS_MXType", "DomainName='{0}'", zoneName);
@ -158,6 +160,14 @@ namespace WebsitePanel.Providers.DNS
records.Add(record);
}
foreach (ManagementObject rr in rrsAAAA) {
record = new DnsRecord();
record.RecordType = DnsRecordType.AAAA;
record.RecordName = CorrectHost(zoneName, (string)rr.Properties["OwnerName"].Value);
record.RecordData = (string)rr.Properties["RecordData"].Value;
records.Add(record);
}
foreach (ManagementObject rr in rrsCNAME)
{
record = new DnsRecord();
@ -448,6 +458,8 @@ namespace WebsitePanel.Providers.DNS
{
if (record.RecordType == DnsRecordType.A)
AddARecord(zoneName, record.RecordName, record.RecordData);
else if (record.RecordType == DnsRecordType.AAAA)
AddAAAARecord(zoneName, record.RecordName, record.RecordData);
else if (record.RecordType == DnsRecordType.CNAME)
AddCNameRecord(zoneName, record.RecordName, record.RecordData);
else if (record.RecordType == DnsRecordType.MX)
@ -481,6 +493,8 @@ namespace WebsitePanel.Providers.DNS
{
if (record.RecordType == DnsRecordType.A)
DeleteARecord(zoneName, record.RecordName, record.RecordData);
else if (record.RecordType == DnsRecordType.AAAA)
DeleteAAAARecord(zoneName, record.RecordName, record.RecordData);
else if (record.RecordType == DnsRecordType.CNAME)
DeleteCNameRecord(zoneName, record.RecordName, record.RecordData);
else if (record.RecordType == DnsRecordType.MX)
@ -689,6 +703,57 @@ namespace WebsitePanel.Providers.DNS
}
#endregion
#region AAAA Record
/// <summary>
///
/// </summary>
/// <param name="zoneName"></param>
/// <param name="host"></param>
/// <param name="ip"></param>
/// <remarks>Supports managed resources disposal</remarks>
private void AddAAAARecord(string zoneName, string host, string ip) {
// add record
using (ManagementClass clsRR = wmi.GetClass("MicrosoftDNS_AAAAType")) {
clsRR.InvokeMethod("CreateInstanceFromPropertyData", new object[] {
GetDnsServerName(),
zoneName,
CorrectHostName(zoneName, host),
1,
MinimumTTL,
ip
});
}
// update SOA record
if (bulkRecords) return;
UpdateSoaRecord(zoneName);
}
/// <summary>
/// Supports managed resources disposal
/// </summary>
/// <param name="zoneName"></param>
/// <param name="host"></param>
/// <param name="ip"></param>
private void DeleteAAAARecord(string zoneName, string host, string ip) {
string query = String.Format("SELECT * FROM MicrosoftDNS_AAAAType " +
"WHERE ContainerName = '{0}' AND OwnerName = '{1}'",
zoneName, CorrectHostName(zoneName, host));
if (ip != null)
query += String.Format(" AND RecordData = '{0}'", ip);
using (ManagementObjectCollection objRRs = wmi.ExecuteQuery(query)) {
foreach (ManagementObject objRR in objRRs) using (objRR)
objRR.Delete();
}
// update SOA record
UpdateSoaRecord(zoneName);
}
#endregion
#region CNAME Record
/// <summary>
///

View file

@ -101,6 +101,9 @@ namespace WebsitePanel.Providers.DNS
case "A":
dnsRecord.RecordType = DnsRecordType.A;
break;
case "AAAA":
dnsRecord.RecordType = DnsRecordType.AAAA;
break;
case "MX":
dnsRecord.RecordType = DnsRecordType.MX;
break;

View file

@ -1058,6 +1058,10 @@ namespace WebsitePanel.Providers.DNS
{
case "A":
result = DnsRecordType.A;
break;
case "AAAA":
result = DnsRecordType.AAAA;
break;
case "CNAME":
@ -1098,6 +1102,10 @@ namespace WebsitePanel.Providers.DNS
result = "A";
break;
case DnsRecordType.AAAA:
result = "AAAA";
break;
case DnsRecordType.CNAME:
result = "CNAME";
break;

View file

@ -190,6 +190,8 @@ namespace WebsitePanel.Providers.DNS
{
if (record.RecordType == DnsRecordType.A)
AddARecord(zoneName, record.RecordName, record.RecordData);
else if (record.RecordType == DnsRecordType.AAAA)
AddAAAARecord(zoneName, record.RecordName, record.RecordData);
else if (record.RecordType == DnsRecordType.CNAME)
AddCNameRecord(zoneName, record.RecordName, record.RecordData);
else if (record.RecordType == DnsRecordType.MX)
@ -225,7 +227,7 @@ namespace WebsitePanel.Providers.DNS
{
try
{
if (record.RecordType == DnsRecordType.A || record.RecordType == DnsRecordType.CNAME)
if (record.RecordType == DnsRecordType.A || record.RecordType == DnsRecordType.AAAA || record.RecordType == DnsRecordType.CNAME)
record.RecordName = CorrectRecordName(zoneName, record.RecordName);
// delete record
@ -254,7 +256,7 @@ namespace WebsitePanel.Providers.DNS
}
#endregion
#region A records
#region A & AAAA records
private void AddARecord(string zoneName, string host, string ip)
{
// get all zone records
@ -285,6 +287,34 @@ namespace WebsitePanel.Providers.DNS
UpdateZone(zoneName, records);
}
private void AddAAAARecord(string zoneName, string host, string ip) {
// get all zone records
List<DnsRecord> records = GetZoneRecordsArrayList(zoneName);
// delete AAAA record
//DeleteARecordInternal(records, zoneName, host);
//check if user tries to add existent zone record
foreach (DnsRecord dnsRecord in records) {
if ((String.Compare(dnsRecord.RecordName, host, StringComparison.OrdinalIgnoreCase) == 0)
&& (String.Compare(dnsRecord.RecordData, ip, StringComparison.OrdinalIgnoreCase) == 0)
)
return;
}
// add new AAAA record
DnsRecord record = new DnsRecord();
record.RecordType = DnsRecordType.AAAA;
record.RecordName = host;
record.RecordData = ip;
records.Add(record);
// update zone
UpdateZone(zoneName, records);
}
private void DeleteRecord(string zoneName, DnsRecordType recordType,
string recordName, string recordData)
{
@ -576,6 +606,15 @@ namespace WebsitePanel.Providers.DNS
r.RecordText = zfLine;
records.Add(r);
}
else if (recordType == "AAAA") // A record
{
DnsRecord r = new DnsRecord();
r.RecordType = DnsRecordType.AAAA;
r.RecordName = CorrectRecordName(zoneName, recordName);
r.RecordData = recordData;
r.RecordText = zfLine;
records.Add(r);
}
else if (recordType == "CNAME") // CNAME record
{
DnsRecord r = new DnsRecord();
@ -696,6 +735,12 @@ namespace WebsitePanel.Providers.DNS
data = rr.RecordData;
name = BuildRecordName(zoneName, host);
}
else if (rr.RecordType == DnsRecordType.AAAA) {
type = "AAAA";
host = rr.RecordName;
data = rr.RecordData;
name = BuildRecordName(zoneName, host);
}
else if (rr.RecordType == DnsRecordType.NS)
{
type = "NS";

View file

@ -89,6 +89,8 @@ namespace WebsitePanel.Providers.DNS
{
// A record
{ DnsRecordType.A, new BuildDnsRecordDataEventHandler(BuildRecordData_ARecord) },
// AAAA record
{ DnsRecordType.AAAA, new BuildDnsRecordDataEventHandler(BuildRecordData_AAAARecord) },
// NS record
{ DnsRecordType.NS, new BuildDnsRecordDataEventHandler(BuildRecordData_NSRecord) },
// CNAME
@ -148,6 +150,13 @@ namespace WebsitePanel.Providers.DNS
RecordData = record.DataFields[0]
};
break;
case "AAAA":
dnsRecord = new DnsRecord {
RecordName = recordName,
RecordType = DnsRecordType.AAAA,
RecordData = record.DataFields[0]
};
break;
case "NS":
dnsRecord = new DnsRecord
{
@ -531,6 +540,12 @@ namespace WebsitePanel.Providers.DNS
//
dnsZone.Records.Add(m_strRecordName, "A", rr.RecordData);
break;
case DnsRecordType.AAAA:
// cleanup DNS record if exists
dnsZone.Records.Remove(m_strRecordName, "AAAA");
//
dnsZone.Records.Add(m_strRecordName, "AAAA", rr.RecordData);
break;
case DnsRecordType.NS:
// cleanup DNS record if exists
dnsZone.Records.Remove(m_strRecordName, "NS");
@ -583,6 +598,8 @@ namespace WebsitePanel.Providers.DNS
{
if (r_type == DnsRecordType.A)
return "A";
else if (r_type == DnsRecordType.AAAA)
return "AAAA";
else if (r_type == DnsRecordType.CNAME)
return "CNAME";
else if (r_type == DnsRecordType.MX)
@ -610,6 +627,13 @@ namespace WebsitePanel.Providers.DNS
data.Add(record.RecordData);
}
static void BuildRecordData_AAAARecord(string zoneName, ref string type,
DnsRecord record, List<string> data)
{
type = "AAAA";
data.Add(record.RecordData);
}
static void BuildRecordData_NSRecord(string zoneName, ref string type,
DnsRecord record, List<string> data)
{

View file

@ -74,6 +74,7 @@
<td class="NormalBold">
<asp:DropDownList ID="ddlRecordType" runat="server" SelectedValue='<%# Bind("RecordType") %>' CssClass="NormalTextBox" AutoPostBack="True" OnSelectedIndexChanged="ddlRecordType_SelectedIndexChanged">
<asp:ListItem>A</asp:ListItem>
<asp:ListItem>AAAA</asp:ListItem>
<asp:ListItem>MX</asp:ListItem>
<asp:ListItem>NS</asp:ListItem>
<asp:ListItem>TXT</asp:ListItem>
@ -91,11 +92,11 @@
<tr id="rowData" runat="server">
<td class="SubHead"><asp:Label ID="lblRecordData" runat="server" meta:resourcekey="lblRecordData" Text="Record Data:"></asp:Label></td>
<td class="NormalBold" nowrap>
<asp:TextBox ID="txtRecordData" runat="server" Width="200px" CssClass="NormalTextBox"></asp:TextBox>
<asp:TextBox ID="txtRecordData" runat="server" Width="260px" CssClass="NormalTextBox"></asp:TextBox>
<asp:RequiredFieldValidator ID="valRequireData" runat="server" ControlToValidate="txtRecordData"
ErrorMessage="*" ValidationGroup="DnsZoneRecord" Display="Dynamic"></asp:RequiredFieldValidator>
<asp:regularexpressionvalidator id="IPValidator" runat="server" ValidationExpression="^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$"
Display="Dynamic" ErrorMessage="Please enter a valid IP" ValidationGroup="DnsZoneRecord" ControlToValidate="txtRecordData" CssClass="NormalBold"></asp:regularexpressionvalidator>
<asp:CustomValidator ID="IPValidator" runat="server" ControlToValidate="txtRecordData" ValidationGroup="DnsZoneRecord" Display="Dynamic" CssClass="NormalBold"
Text="Please enter a valid IP" OnServerValidate="Validate" meta:resourcekey="IPValidator" />
</td>
</tr>
@ -104,9 +105,9 @@
<td class="NormalBold">
<asp:TextBox ID="txtMXPriority" runat="server" Width="30" CssClass="NormalTextBox"></asp:TextBox>
<asp:RequiredFieldValidator ID="valRequireMxPriority" runat="server" ControlToValidate="txtMXPriority"
ErrorMessage="*" ValidationGroup="DnsZoneRecord" Display="Dynamic"></asp:RequiredFieldValidator>
ErrorMessage="*" ValidationGroup="DnsZoneRecord" Display="Dynamic" />
<asp:RegularExpressionValidator ID="valRequireCorrectPriority" runat="server" ControlToValidate="txtMXPriority"
ErrorMessage="*" ValidationExpression="\d{1,3}"></asp:RegularExpressionValidator></td>
ErrorMessage="*" ValidationExpression="\d{1,3}" ValidationGroup="DnsZoneRecord" /></td>
</tr>
<tr id="rowSRVPriority" runat="server">

View file

@ -129,6 +129,10 @@ namespace WebsitePanel.Portal
lblRecordData.Text = "IP:";
IPValidator.Enabled = true;
break;
case "AAAA":
lblRecordData.Text = "IP (v6):";
IPValidator.Enabled = true;
break;
case "MX":
rowMXPriority.Visible = true;
break;
@ -142,6 +146,15 @@ namespace WebsitePanel.Portal
break;
}
}
protected void Validate(object source, ServerValidateEventArgs args) {
var ip = args.Value;
System.Net.IPAddress ipaddr;
args.IsValid = System.Net.IPAddress.TryParse(ip, out ipaddr) && (ip.Contains(":") || ip.Contains(".")) &&
((ddlRecordType.SelectedValue == "A" && ipaddr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) ||
(ddlRecordType.SelectedValue == "AAAA" && ipaddr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6));
}
private void SaveRecord()

View file

@ -201,7 +201,7 @@ namespace WebsitePanel.Portal {
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.RegularExpressionValidator IPValidator;
protected global::System.Web.UI.WebControls.CustomValidator IPValidator;
/// <summary>
/// rowMXPriority control.

View file

@ -116,6 +116,7 @@
<td class="NormalBold" width="100%">
<asp:DropDownList ID="ddlRecordType" runat="server" SelectedValue='<%# Bind("RecordType") %>' CssClass="NormalTextBox" AutoPostBack="True" OnSelectedIndexChanged="ddlRecordType_SelectedIndexChanged">
<asp:ListItem>A</asp:ListItem>
<asp:ListItem>AAAA</asp:ListItem>
<asp:ListItem>MX</asp:ListItem>
<asp:ListItem>NS</asp:ListItem>
<asp:ListItem>TXT</asp:ListItem>
@ -133,7 +134,7 @@
<tr id="rowData" runat="server">
<td class="SubHead"><asp:Label ID="lblRecordData" runat="server" meta:resourcekey="lblRecordData" Text="Record Data:"></asp:Label></td>
<td class="NormalBold" nowrap>
<asp:TextBox ID="txtRecordData" runat="server" Width="200px" CssClass="NormalTextBox"></asp:TextBox>
<asp:TextBox ID="txtRecordData" runat="server" Width="260px" CssClass="NormalTextBox"></asp:TextBox>
<asp:RequiredFieldValidator ID="valRequireData" runat="server" ControlToValidate="txtRecordData"
ErrorMessage="*" ValidationGroup="DnsZoneRecord" Display="Dynamic"></asp:RequiredFieldValidator>
<asp:regularexpressionvalidator id="IPValidator" runat="server" ValidationExpression="^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$"
@ -142,8 +143,8 @@
</tr>
<tr>
<asp:regularexpressionvalidator id="IPValidator1" runat="server" ValidationExpression="^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$"
Display="Dynamic" ErrorMessage="Please enter a valid IP" ValidationGroup="DnsZoneRecord" ControlToValidate="txtRecordData" CssClass="NormalBold"></asp:regularexpressionvalidator>
<asp:CustomValidator ID="IPValidator" runat="server" ControlToValidate="txtRecordData" ValidationGroup="DnsZoneRecord" Display="Dynamic"
OnServerValidate="Validate" Text="Please enter a valid IP" meta:resourcekey="IPValidator" />
</tr>
<tr id="rowMXPriority" runat="server">
<td class="SubHead"><asp:Label ID="lblMXPriority" runat="server" meta:resourcekey="lblMXPriority" Text="MX Priority:"></asp:Label></td>

View file

@ -140,6 +140,10 @@ namespace WebsitePanel.Portal.ExchangeServer
lblRecordData.Text = "IP:";
IPValidator.Enabled = true;
break;
case "AAAA":
lblRecordData.Text = "IP (v6):";
IPValidator.Enabled = true;
break;
case "MX":
rowMXPriority.Visible = true;
break;
@ -154,6 +158,14 @@ namespace WebsitePanel.Portal.ExchangeServer
}
}
protected void Validate(object source, ServerValidateEventArgs args) {
var ip = args.Value;
System.Net.IPAddress ipaddr;
args.IsValid = System.Net.IPAddress.TryParse(ip, out ipaddr) && (ip.Contains(":") || ip.Contains(".")) &&
((ddlRecordType.SelectedValue == "A" && ipaddr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) ||
(ddlRecordType.SelectedValue == "AAAA" && ipaddr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6));
}
private void SaveRecord()
{
if (!Page.IsValid)

View file

@ -238,13 +238,12 @@ namespace WebsitePanel.Portal.ExchangeServer {
protected global::System.Web.UI.WebControls.RegularExpressionValidator IPValidator;
/// <summary>
/// IPValidator1 control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.RegularExpressionValidator IPValidator1;
protected global::System.Web.UI.WebControls.CustomValidator IPValidator;
/// <summary>
/// rowMXPriority control.

View file

@ -35,6 +35,7 @@
<td class="Normal" width="100%">
<asp:DropDownList ID="ddlRecordType" runat="server" SelectedValue='<%# Bind("RecordType") %>' CssClass="NormalTextBox" AutoPostBack="True" OnSelectedIndexChanged="ddlRecordType_SelectedIndexChanged">
<asp:ListItem>A</asp:ListItem>
<asp:ListItem>AAAA</asp:ListItem>
<asp:ListItem>MX</asp:ListItem>
<asp:ListItem>NS</asp:ListItem>
<asp:ListItem>TXT</asp:ListItem>
@ -52,13 +53,21 @@
<tr id="rowData" runat="server">
<td class="SubHead"><asp:Label ID="lblRecordData" runat="server" meta:resourcekey="lblRecordData" Text="Record Data:"></asp:Label></td>
<td class="Normal" nowrap>
<asp:TextBox ID="txtRecordData" runat="server" Width="200px" CssClass="NormalTextBox"></asp:TextBox><uc1:SelectIPAddress ID="ipAddress" runat="server" />
<asp:TextBox ID="txtRecordData" runat="server" Width="260px" CssClass="NormalTextBox"></asp:TextBox><uc1:SelectIPAddress ID="ipAddress" runat="server" />
<asp:RequiredFieldValidator ID="valRequireData" runat="server" ControlToValidate="txtRecordData"
ErrorMessage="*" ValidationGroup="DnsRecord" Display="Dynamic"></asp:RequiredFieldValidator>
<asp:CustomValidator ID="IPValidator" runat="server" ControlToValidate="txtRecordData" ValidationGroup="DnsRecord" Display="Dynamic" CssClass="NormalBold"
OnServerValidate="Validate" Text="Please enter a valid IP" meta:resourcekey="IPValidator"/>
</td>
</tr>
<tr id="rowMXPriority" runat="server">
<td class="SubHead"><asp:Label ID="lblMXPriority" runat="server" meta:resourcekey="lblMXPriority" Text="MX Priority:"></asp:Label></td>
<td class="Normal">
<asp:TextBox ID="txtMXPriority" runat="server" Width="30" CssClass="NormalTextBox"></asp:TextBox>
<asp:RequiredFieldValidator ID="valRequireMxPriority" runat="server" ControlToValidate="txtMXPriority"
ErrorMessage="*" ValidationGroup="DnsRecord" Display="Dynamic"></asp:RequiredFieldValidator>
<asp:RegularExpressionValidator ID="valRequireCorrectPriority" runat="server" ControlToValidate="txtMXPriority"
ErrorMessage="*" ValidationExpression="\d{1,3}" ValidationGroup="DnsRecord" />
</td>
</tr>

View file

@ -144,7 +144,6 @@ namespace WebsitePanel.Portal
private void ToggleRecordControls()
{
rowMXPriority.Visible = false;
rowSRVPriority.Visible = false;
rowSRVWeight.Visible = false;
@ -158,6 +157,10 @@ namespace WebsitePanel.Portal
lblRecordData.Text = "IP:";
ipAddress.Visible = true;
break;
case "AAAA":
lblRecordData.Text = "IP (v6):";
ipAddress.Visible = true;
break;
case "MX":
rowMXPriority.Visible = true;
break;
@ -165,15 +168,25 @@ namespace WebsitePanel.Portal
rowSRVPriority.Visible = true;
rowSRVWeight.Visible = true;
rowSRVPort.Visible = true;
lblRecordData.Text = "Host offering this service:";
break;
default:
break;
}
}
protected void Validate(object source, ServerValidateEventArgs args) {
var ip = args.Value;
System.Net.IPAddress ipaddr;
args.IsValid = System.Net.IPAddress.TryParse(ip, out ipaddr) && (ip.Contains(":") || ip.Contains(".")) &&
((ddlRecordType.SelectedValue == "A" && ipaddr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) ||
(ddlRecordType.SelectedValue == "AAAA" && ipaddr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6));
}
private void SaveRecord()
{
if (!Page.IsValid) return;
GlobalDnsRecord record = new GlobalDnsRecord();
record.RecordId = (int)ViewState["RecordID"];
record.RecordType = ddlRecordType.SelectedValue;

View file

@ -8,6 +8,8 @@
<asp:ValidationSummary ID="validatorsSummary" runat="server"
ValidationGroup="EditAddress" ShowMessageBox="True" ShowSummary="False" />
<asp:CustomValidator ID="consistentAddresses" runat="server" ErrorMessage="You must not mix IPv4 and IPv6 addresses." ValidationGroup="EditAddress" Display="dynamic" ServerValidate="CheckIPAddresses" />
<table cellspacing="0" cellpadding="3">
<tr>
<td style="width:150px;">
@ -33,7 +35,7 @@
<td><asp:Localize ID="lblExternalIP" runat="server" meta:resourcekey="lblExternalIP" Text="IP Address:"></asp:Localize></td>
<td>
<wsp:EditIPAddressControl id="startIP" runat="server" ValidationGroup="EditAddress" Required="true" />
<wsp:EditIPAddressControl id="startIP" runat="server" ValidationGroup="EditAddress" Required="true" AllowSubnet="true" />
&nbsp;<asp:Localize ID="locTo" runat="server" meta:resourcekey="locTo" Text="to"></asp:Localize>&nbsp;
@ -52,7 +54,7 @@
<tr id="SubnetRow" runat="server">
<td><asp:Localize ID="locSubnetMask" runat="server" meta:resourcekey="locSubnetMask" Text="Subnet Mask:"></asp:Localize></td>
<td class="NormalBold">
<wsp:EditIPAddressControl id="subnetMask" runat="server" ValidationGroup="EditAddress" Required="true" />
<wsp:EditIPAddressControl id="subnetMask" runat="server" ValidationGroup="EditAddress" Required="true" AllowSubnet="true" />
</td>
</tr>
<tr id="GatewayRow" runat="server">

View file

@ -49,6 +49,7 @@ namespace WebsitePanel.Portal
{
if (!IsPostBack)
{
// bind dropdowns
try
{
@ -96,7 +97,7 @@ namespace WebsitePanel.Portal
string comments = txtComments.Text.Trim();
// add ip address
if (endIP.Text != "")
if (endIP.Text != "" || startIP.Text.Contains("/"))
{
try
{
@ -162,5 +163,12 @@ namespace WebsitePanel.Portal
SubnetRow.Visible = vps;
GatewayRow.Visible = vps;
}
public void CheckIPAddresses(object sender, ServerValidateEventArgs args) {
startIP.Validate(sender, args);
endIP.Validate(sender, args);
subnetMask.Validate(sender, args);
args.IsValid = startIP.IsV6 == endIP.IsV6 && (startIP.IsV6 == subnetMask.IsV6 || subnetMask.IsMask);
}
}
}

View file

@ -1,7 +1,6 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.1434
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@ -31,6 +30,15 @@ namespace WebsitePanel.Portal {
/// </remarks>
protected global::System.Web.UI.WebControls.ValidationSummary validatorsSummary;
/// <summary>
/// consistent Addresses control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.CustomValidator consistentAddresses;
/// <summary>
/// locPool control.
/// </summary>

View file

@ -288,7 +288,7 @@
<td>
<wsp:EditIPAddressControl id="privateIPAddress" runat="server" Required="true" />
/
<asp:TextBox ID="privateSubnetMask" runat="server" MaxLength="2" Width="40px" CssClass="NormalTextBox"></asp:TextBox>
<asp:TextBox ID="privateSubnetMask" runat="server" MaxLength="3" Width="40px" CssClass="NormalTextBox"></asp:TextBox>
<asp:RequiredFieldValidator ID="privateSubnetMaskValidator" runat="server" ControlToValidate="privateSubnetMask"
Text="*" meta:resourcekey="privateSubnetMaskValidator" Display="Dynamic" SetFocusOnError="true" />
</td>

View file

@ -1,7 +1,6 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.4927
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.

View file

@ -1,8 +1,5 @@
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="EditIPAddressControl.ascx.cs" Inherits="WebsitePanel.Portal.UserControls.EditIPAddressControl" %>
<asp:TextBox ID="txtAddress" runat="server" Width="110px" MaxLength="15" CssClass="NormalTextBox"></asp:TextBox>
<asp:TextBox ID="txtAddress" runat="server" Width="260px" MaxLength="45" CssClass="NormalTextBox"></asp:TextBox>
<asp:RequiredFieldValidator ID="requireAddressValidator" runat="server" meta:resourcekey="requireAddressValidator"
ControlToValidate="txtAddress" SetFocusOnError="true" Text="*" Enabled="false" Display="Dynamic">
</asp:RequiredFieldValidator><asp:RegularExpressionValidator id="addressValidator" runat="server"
ValidationExpression="^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$"
Display="Dynamic" SetFocusOnError="true" ControlToValidate="txtAddress" Text="*" meta:resourcekey="addressValidator">
</asp:RegularExpressionValidator>
ControlToValidate="txtAddress" SetFocusOnError="true" Text="*" Enabled="false" Display="Dynamic" />
<asp:CustomValidator ID="addressValidator" runat="server" ControlToValidate="txtAddress" OnServerValidate="Validate" Text="*" meta:resourcekey="addressValidator"/>

View file

@ -34,8 +34,16 @@ using System.Web.UI.WebControls;
namespace WebsitePanel.Portal.UserControls
{
[Flags]
public enum IPValidationMode { V4 = 1, V6 = 2, V4AndV6 = 3 };
public partial class EditIPAddressControl : WebsitePanelControlBase
{
public IPValidationMode Validation { get; set; }
public EditIPAddressControl() { Validation = IPValidationMode.V4AndV6; AllowSubnet = false; }
public bool Required
{
get { return requireAddressValidator.Enabled; }
@ -86,5 +94,30 @@ namespace WebsitePanel.Portal.UserControls
{
}
public bool AllowSubnet { get; set; }
public bool IsV6 { get; private set; }
public bool IsMask { get; private set; }
public void Validate(object source, ServerValidateEventArgs args) {
IsMask = IsV6 = false;
var ip = args.Value;
int net = 0;
if (ip.Contains("/")) {
args.IsValid = AllowSubnet;
var tokens = ip.Split('/');
ip = tokens[0];
args.IsValid &= int.TryParse(tokens[1], out net) && net <= 128;
if (string.IsNullOrEmpty(ip)) {
IsMask = true;
return;
}
}
System.Net.IPAddress ipaddr;
args.IsValid &= System.Net.IPAddress.TryParse(ip, out ipaddr) && (ip.Contains(":") || ip.Contains(".")) &&
(((Validation & IPValidationMode.V6) != 0 && (IsV6 = ipaddr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)) ||
((Validation & IPValidationMode.V4) != 0 && ipaddr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork));
args.IsValid &= ipaddr.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork || net < 32;
}
}
}

View file

@ -1,7 +1,6 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.1434
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@ -38,6 +37,6 @@ namespace WebsitePanel.Portal.UserControls {
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.RegularExpressionValidator addressValidator;
protected global::System.Web.UI.WebControls.CustomValidator addressValidator;
}
}

View file

@ -6,7 +6,6 @@
<add tagPrefix="ajaxToolkit" namespace="AjaxControlToolkit" assembly="AjaxControlToolkit"/>
</controls>
</pages>
<compilation targetFramework="4.0">
</compilation>
<compilation targetFramework="4.0" debug="true"/>
</system.web>
</configuration>