//バイトイメージの取得 public byte[] GetBytes() { var buffer = _dnsHeader.GetBytes(); for (var i = 0; i < 4; i++) { var a = _ar[i]; foreach (var o in a) { var dataName = (new Compress(buffer, DnsUtil.Str2DnsName(o.Name))).GetData(); var data = o.Data; var dnsType = o.DnsType; if (i != 0) { //QDでは、data部分は存在しない if (dnsType == DnsType.Ns || dnsType == DnsType.Cname || dnsType == DnsType.Ptr) { data = (new Compress(buffer, o.Data)).GetData(); //圧縮 } else if (dnsType == DnsType.Mx) { var preference = Conv.GetUShort(o.Data, 0); var mlServer = new byte[o.Data.Length - 2]; //System.arraycopy(o.Data, 2, mlServer, 0, o.Data.Length - 2); Buffer.BlockCopy(o.Data, 2, mlServer, 0, o.Data.Length - 2); mlServer = (new Compress(buffer, mlServer)).GetData(); //圧縮 data = Bytes.Create(Conv.GetBytes(preference), mlServer); } } //PacketRrは、QD(i==0)の時、data.Length=0となり、内部でisQueryがセットされる var packetRr = new PacketRr(data.Length); try{ packetRr.Cls = 1; packetRr.DnsType = dnsType; packetRr.Ttl = o.Ttl; //PacketRr.isQueryがセットされているとき、処理なし packetRr.Data = data; //PacketRr.isQueryがセットされているとき、処理なし } catch (IOException e) { //設計上の問題 Util.RuntimeException(e.Message); } //PacketRr.isQueryがセットされているとき、getBytes()は4バイト(TTL,DLEN,DATAなし)になっている buffer = Bytes.Create(buffer, dataName, packetRr.GetBytes()); } } return(buffer); }
public RrSoa(string name, uint ttl, string n1, string n2, uint serial, uint refresh, uint retry, uint expire, uint minimum) : base(name, DnsType.Soa, ttl, Bytes.Create(DnsUtil.Str2DnsName(n1), DnsUtil.Str2DnsName(n2), Conv.GetBytes(serial), Conv.GetBytes(refresh), Conv.GetBytes(retry), Conv.GetBytes(expire), Conv.GetBytes(minimum))) { }
protected override void OnSubThread(SockObj sockObj) { var sockUdp = (SockUdp)sockObj; //セッションごとの情報 //Session session = new Session((SockTcp) sockObj); PacketDns rp; //受信パケット try { //パケットの読込(受信パケットrp) var buf = sockUdp.RecvBuf; if (buf.Length < 12) { return; } rp = new PacketDns(sockUdp.RecvBuf); } catch (IOException) { //データ解釈に失敗した場合は、処理なし Logger.Set(LogKind.Secure, sockUdp, 4, ""); //不正パケットの可能性あり return; } //リクエストのドメイン名を取得する var domainName = InitRequestDomain(rp.GetRequestName(), rp.GetDnsType()); //リクエスト解釈完了 Logger.Set(LogKind.Normal, sockUdp, 8, string.Format("{0} {1} domain={2}", rp.GetDnsType(), rp.GetRequestName(), domainName)); //Query var aa = false; // ドメインオーソリティ(管理ドメインかそうでないか) const bool ra = true; //再帰可能 var targetCache = _rootCache; //デフォルトはルートキャッシュ if (rp.GetDnsType() == DnsType.Ptr) { if (rp.GetRequestName().ToUpper() == "1.0.0.127.IN-ADDR.ARPA." || rp.GetRequestName().ToUpper() == "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA." || rp.GetRequestName().ToUpper() == "LOCALHOST.") { //キャッシュはデフォルトであるルートキャッシュが使用される aa = true; Logger.Set(LogKind.Detail, sockUdp, 9, ""); //"request to a domain under auto (localhost)" } else { foreach (var cache in _cacheList) { if (cache.Find(rp.GetRequestName(), DnsType.Ptr)) { targetCache = cache; aa = true; Logger.Set(LogKind.Detail, sockUdp, 10, string.Format("Resource={0}", targetCache.GetDomainName())); //"request to a domain under management" break; } } } } else { //A if (rp.GetRequestName().ToUpper() == "LOCALHOST.") { //キャッシュはデフォルトであるルートキャッシュが使用される aa = true; Logger.Set(LogKind.Detail, sockUdp, 11, ""); //"request to a domain under auto (localhost)" } else { foreach (var cache in _cacheList) { if (cache.GetDomainName().ToUpper() == domainName.ToUpper()) { //大文字で比較される targetCache = cache; aa = true; Logger.Set(LogKind.Detail, sockUdp, 12, string.Format("Resource={0}", domainName)); //"request to a domain under management" break; } } } } //管理するドメインでなく、かつ 再帰要求が無い場合は、処理を終わる if (!(aa) && !(rp.GetRd())) { return; } //aa ドメインオーソリティ //rs 再帰可能 //rd 再起要求あり // (A)「ヘッダ」作成 const bool qr = true; //応答 //******************************************************** //パケットの生成(送信パケットsp) //******************************************************** //Ver6.1.0 again: var sp = new PacketDns(rp.GetId(), qr, aa, rp.GetRd(), ra); // (B)「質問セクション」の追加 AppendRr(sp, RrKind.QD, new RrQuery(rp.GetRequestName(), rp.GetDnsType())); //質問フィールドの追加 if (!aa) { //ドメインオーソリティ(権威サーバ)で無い場合 //ルートキャッシュにターゲットのデータが蓄積されるまで、再帰的に検索する try { SearchLoop(rp.GetRequestName(), rp.GetDnsType(), sockUdp.RemoteIp); } catch (IOException) { // ここはどうやって扱えばいいか??? //e.printStackTrace(); } } // (B)「回答セクション」作成 var ansList = targetCache.GetList(rp.GetRequestName(), rp.GetDnsType()); //Ver6.1.0 (リソースに無い場合は、再帰検索に入る) if (ansList.Count == 0 && aa && !targetCache.Authority) { targetCache = _rootCache; //ルートキャッシュに戻す aa = false; goto again; } //Ver5.9.4 Aレコードを検索してCNAMEしか帰らない場合の処理 // if (ansList.Count == 0 && rp.GetDnsType() == DnsType.A){ // foreach (RrCname o in targetCache.GetList(rp.GetRequestName(), DnsType.Cname)) { // ansList.Add(o); // var list = targetCache.GetList(o.CName, DnsType.A); // foreach (var l in list){ // ansList.Add(l); // } // } // } Logger.Set(LogKind.Detail, sockUdp, 13, string.Format("{0} ansList.Count={1}", rp.GetDnsType(), ansList.Count)); //"Create Response (AN)" if (0 < ansList.Count) { //検索でヒットした場合 foreach (var oneRr in ansList) { AppendRr(sp, RrKind.AN, DnsUtil.CreateRr(rp.GetRequestName(), rp.GetDnsType(), oneRr.Ttl, oneRr.Data)); if (rp.GetDnsType() == DnsType.Mx || rp.GetDnsType() == DnsType.Cname || rp.GetDnsType() == DnsType.Ns) { var targetName = ""; if (rp.GetDnsType() == DnsType.Mx) { targetName = ((RrMx)oneRr).MailExchangeHost; } else if (rp.GetDnsType() == DnsType.Ns) { targetName = ((RrNs)oneRr).NsName; } else if (rp.GetDnsType() == DnsType.Cname) { targetName = ((RrCname)oneRr).CName; } else { Util.RuntimeException("not implement [Server.onSubThread()]"); } //追加情報が必要な場合 (Aレコード)をパケットに追加する var rr = targetCache.GetList(targetName, DnsType.A); foreach (OneRr r in rr) { AppendRr(sp, RrKind.AR, new RrA(targetName, r.Ttl, r.Data)); } //追加情報が必要な場合 (AAAAレコード)をパケットに追加する rr = targetCache.GetList(targetName, DnsType.Aaaa); foreach (var r in rr) { AppendRr(sp, RrKind.AR, new RrAaaa(targetName, r.Ttl, r.Data)); } } } } else { //検索でヒットしない場合 if (rp.GetDnsType() == DnsType.A) { // CNAMEに定義されていないかどうかを確認する //Ver5.9.4 再帰的にCNAMEを検索する //var cnameList = targetCache.GetList(rp.GetRequestName(), DnsType.Cname); var cnameList = new List <OneRr>(); cnameList = GetAllCname(targetCache, rp.GetRequestName(), cnameList); foreach (var o in cnameList) { Logger.Set(LogKind.Detail, sockUdp, 16, o.ToString()); //"Append RR" AppendRr(sp, RrKind.AN, o); var cname = ((RrCname)o).CName; var aList = targetCache.GetList(cname, DnsType.A); foreach (var a in aList) { // Logger.Set(LogKind.Detail, sockUdp, 16, o.ToString()); //"Append RR" // AppendRr(sp, RrKind.AN, o); Logger.Set(LogKind.Detail, sockUdp, 16, a.ToString()); //"Append RR" AppendRr(sp, RrKind.AN, a); } } } } if (rp.GetDnsType() == DnsType.A || rp.GetDnsType() == DnsType.Aaaa || rp.GetDnsType() == DnsType.Soa || rp.GetDnsType() == DnsType.Cname) { // (C)「権威セクション」「追加情報セクション」作成 var nsList = targetCache.GetList(domainName, DnsType.Ns); Logger.Set(LogKind.Detail, sockUdp, 22, string.Format("{0} nsList.Count={1}", DnsType.Ns, nsList.Count)); // Create Response (AR) foreach (var o in nsList) { var ns = (RrNs)o; AppendRr(sp, RrKind.NS, new RrNs(ns.Name, ns.Ttl, ns.Data)); if (domainName.ToUpper() != "LOCALHOST.") { //localhost検索の場合は、追加情報はない //「追加情報」 var addList = targetCache.GetList(ns.NsName, DnsType.A); foreach (OneRr rr in addList) { AppendRr(sp, RrKind.AR, new RrA(ns.NsName, rr.Ttl, rr.Data)); } addList = targetCache.GetList(ns.NsName, DnsType.Aaaa); foreach (OneRr rr in addList) { AppendRr(sp, RrKind.AR, new RrAaaa(ns.NsName, rr.Ttl, rr.Data)); } } } } sockUdp.Send(sp.GetBytes()); //送信 //sockUdp.Close();UDPソケット(sockUdp)はクローンなのでクローズしても、処理されない※Close()を呼び出しても問題はない sockUdp.Close(); }
public RrMx(string name, uint ttl, ushort preference, string mailExchangerHost) : base(name, DnsType.Mx, ttl, Bytes.Create(Conv.GetBytes(preference), DnsUtil.Str2DnsName(mailExchangerHost))) { }
//リソース定義(Dat)で初期化する場合 public DnsCache(Logger logger, OneOption oneOption, Dat dat, string dName) { const uint ttl = 0; //有効期限なし var ns = ""; //SOA追加時に使用するため、NSレコードを見つけたときにサーバ名を保存しておく //オプションを読み込んで、ローカルデータを初期化する //this.oneOption = oneOption; _soaExpire = (uint)(int)oneOption.GetValue("soaExpire"); DomainName = dName; foreach (var o in dat) { if (o.Enable) { var type = Convert.ToInt32(o.StrList[0]); var name = o.StrList[1]; var alias = o.StrList[2]; var ip = new Ip(o.StrList[3]); var n = Convert.ToInt32(o.StrList[4]); var dnsType = DnsType.A; if (type == 1) { dnsType = DnsType.Ns; } else if (type == 2) { dnsType = DnsType.Mx; } else if (type == 3) { dnsType = DnsType.Cname; } else if (type == 4) { dnsType = DnsType.Aaaa; } var priority = (ushort)n; //uint addr = ip.AddrV4; //class Ip -> uint; //最後に.がついていない場合、ドメイン名を追加する if (name.LastIndexOf('.') != name.Length - 1) { name = name + "." + DomainName; } if (alias.LastIndexOf('.') != alias.Length - 1) { alias = alias + "." + DomainName; } //CNAME以外は、PTRレコードを自動的に生成する if (dnsType != DnsType.Cname) { //PTR名を作成 [例] 192.168.0.1 -> 1.0.168.192.in-addr.arpa; if (ip.InetKind == InetKind.V4) //IPv4 { string ptrName = string.Format("{0}.{1}.{2}.{3}.in-addr.arpa.", ip.IpV4[3], ip.IpV4[2], ip.IpV4[1], ip.IpV4[0]); Add(new OneRR(ptrName, DnsType.Ptr, ttl, DnsUtil.Str2DnsName(name))); } else //IPv6 { var sb = new StringBuilder(); foreach (var a in ip.IpV6) { sb.Append(string.Format("{0:x4}", a)); } string ipStr = sb.ToString(); if (ipStr.Length == 32) { sb = new StringBuilder(); for (int e = 31; e >= 0; e--) { sb.Append(ipStr[e]); sb.Append('.'); } Add(new OneRR(sb + "ip6.arpa.", DnsType.Ptr, ttl, DnsUtil.Str2DnsName(name))); } } } //データベースへの追加 if (dnsType == DnsType.A) { if (ip.InetKind == InetKind.V4) { //ネットワークバイト配列の取得 Add(new OneRR(name, DnsType.A, ttl, ip.NetBytes())); } else { logger.Set(LogKind.Error, null, 19, string.Format("address {0}", ip)); } } else if (dnsType == DnsType.Aaaa) { if (ip.InetKind == InetKind.V6) { Add(new OneRR(name, DnsType.Aaaa, ttl, ip.NetBytes())); } else { logger.Set(LogKind.Error, null, 20, string.Format("address {0}", ip)); } } else if (dnsType == DnsType.Ns) { ns = name;//SOA追加時に使用するため、ネームサーバの名前を保存する // A or AAAAレコードも追加 Add(new OneRR(name, (ip.InetKind == InetKind.V4) ? DnsType.A : DnsType.Aaaa, ttl, ip.NetBytes())); Add(new OneRR(DomainName, DnsType.Ns, ttl, DnsUtil.Str2DnsName(name))); } else if (dnsType == DnsType.Mx) { // A or AAAAレコードも追加 Add(new OneRR(name, DnsType.A, ttl, ip.NetBytes())); //プライオリィ byte[] dataName = DnsUtil.Str2DnsName(name);//DNS名前形式に変換 byte[] data = Bytes.Create(Util.htons(priority), dataName); Add(new OneRR(DomainName, DnsType.Mx, ttl, data)); } else if (dnsType == DnsType.Cname) { Add(new OneRR(alias, DnsType.Cname, ttl, DnsUtil.Str2DnsName(name))); } } //SOAレコードの追加 if (ns != "") //NSサーバ名が必須 { var soaMail = (string)oneOption.GetValue("soaMail"); soaMail.Replace('@', '.'); //@を.に置き換える soaMail = soaMail + "."; //最後に.を追加する var soaSerial = (uint)(int)oneOption.GetValue("soaSerial"); var soaRefresh = (uint)(int)oneOption.GetValue("soaRefresh"); var soaRetry = (uint)(int)oneOption.GetValue("soaRetry"); var soaExpire = (uint)(int)oneOption.GetValue("soaExpire"); var soaMinimum = (uint)(int)oneOption.GetValue("soaMinimum"); byte[] data = Bytes.Create( DnsUtil.Str2DnsName(ns), DnsUtil.Str2DnsName(soaMail), Util.htonl(soaSerial), Util.htonl(soaRefresh), Util.htonl(soaRetry), Util.htonl(soaExpire), Util.htonl(soaMinimum)); Add(new OneRR(DomainName, DnsType.Soa, ttl, data)); } } }
readonly uint _soaExpire;//終了時間(オプションで指定された有効時間) //named.caで初期化する場合 //public DnsCache(Logger logger, OneOption oneOption, string fileName) { public DnsCache(OneOption oneOption, string fileName) { uint ttl = 0;//rootCacheは有効期限なし //オプションを読み込んで、ローカルデータを初期化する //this.oneOption = oneOption; _soaExpire = (uint)(int)oneOption.GetValue("soaExpire"); DomainName = "."; //this.defaultExpire = defaultExpire; if (File.Exists(fileName)) { using (var sr = new StreamReader(fileName, Encoding.GetEncoding("Shift_JIS"))) { var tmpName = "";//全行のNAMEを保持する NAMEは前行と同じ場合省略が可能 while (true) { var name = ""; //string Class = "IN"; var dnsType = DnsType.Unknown; var str = sr.ReadLine(); if (str == null) { break; } //;以降はコメントとして削除する var i = str.IndexOf(';'); if (i != -1) { str = str.Substring(0, i); } //空の行は処理しない if (str.Length == 0) { continue; } //空白・タブを削除して、パラメータをtmp2へ取得する var tmp = str.Split(new[] { ' ', '\t' }); var tmp2 = tmp.Where(s => s != "").ToList(); //************************************************ //タイプだけは省略することができないので、それを基準にサーチする //************************************************ var typeCol = 0; for (; typeCol < tmp2.Count; typeCol++) { foreach (DnsType t in Enum.GetValues(typeof(DnsType))) { if (tmp2[typeCol] != t.ToString().ToUpper()) { continue; } dnsType = t; break; } if (dnsType != DnsType.Unknown) { break; } } if (dnsType == DnsType.Unknown) { goto err;//タイプが見つからない場合は、無効行とする } //タイプの次がDATAとなる if (typeCol + 1 >= tmp2.Count) { goto err; //タイプの次にカラム(DATA)が存在しない } string dataStr = tmp2[typeCol + 1]; //************************************************ //クラス(IN)が含まれているかどうかをサーチする //************************************************ var classCol = 0; for (; classCol < tmp2.Count; classCol++) { if (tmp2[classCol] != "IN") { continue; } goto find; } classCol = -1; find: //クラスが含まれた場合、そのカラムはclassColに保存されている //含まれていない場合 classCol=-1 if (typeCol == 1) { if (classCol == -1) //INが無い場合 //0番目はNAME若しくはTTLとなる { if (str.Substring(0, 1) == " " || str.Substring(0, 1) == "\t") { //名前は省略されているので ttl = Convert.ToUInt32(tmp2[0]); ttl = Util.htonl(ttl); } else { name = tmp2[0]; } } else //INが有る場合 { if (classCol != 0) { goto err;//位置がおかしい } //0番目はINであるので、名前もTTLも省略されている } } else if (typeCol == 2) { if (classCol == -1) //INが無い場合 //0番目はNAME、1番目はTTLとなる { name = tmp2[0]; ttl = Convert.ToUInt32(tmp2[1]); ttl = Util.htonl(ttl); } else //INが有る場合 { if (classCol != 1) { goto err;//位置がおかしい } //0番目はNAME若しくはTTLとなる if (str.Substring(0, 1) == " " || str.Substring(0, 1) == "\t") { //名前は省略されているので ttl = Convert.ToUInt32(tmp2[0]); ttl = Util.htonl(ttl); } else { name = tmp2[0]; } } } else if (typeCol == 3) { if (classCol == -1) //INが無い場合 //カラム不足 { goto err; } //INが有る場合 if (classCol != 2) { goto err;//位置がおかしい } //0番目はNAME、1番目はTTLとなる name = tmp2[0]; ttl = Convert.ToUInt32(tmp2[1]); ttl = Util.htonl(ttl); } //********************************************* //nameの補完 //********************************************* if (name == "@") //@の場合 { name = DomainName; } else if (name.LastIndexOf('.') != name.Length - 1) //最後に.がついていない場合、ドメイン名を追加する { name = name + "." + DomainName + "."; } else if (name == "") { name = tmpName; //前行と同じ } tmpName = name; //前行分として記憶する //********************************************* //string sataStr を変換してデータベースに追加 //********************************************* if (dnsType == DnsType.A) { var ipV4 = new Ip(dataStr); Add(new OneRR(name, dnsType, ttl, ipV4.NetBytes())); } else if (dnsType == DnsType.Ns) { Add(new OneRR(name, dnsType, ttl, DnsUtil.Str2DnsName(dataStr))); } else if (dnsType == DnsType.Aaaa) { var ipV6 = new Ip(dataStr); Add(new OneRR(name, dnsType, ttl, ipV6.NetBytes())); } else { Msg.Show(MsgKind.Error, "name.caには、タイプA,AAAA及びNS以外は使用できません。"); goto err; } continue; err: //行に矛盾が有る Msg.Show(MsgKind.Error, string.Format("ServerDnsCache() レコード読み込みエラー 矛盾があります。[ {0} {1} ]", fileName, str)); } sr.Close(); } } //locaohostレコードの追加 { var ip = new Ip("127.0.0.1"); Add(new OneRR("localhost.", DnsType.A, ttl, ip.NetBytes())); Add(new OneRR("1.0.0.127.in-addr.arpa.", DnsType.Ptr, ttl, DnsUtil.Str2DnsName("localhost"))); ip = new Ip("::1"); Add(new OneRR("localhost.", DnsType.Aaaa, ttl, ip.NetBytes())); Add(new OneRR("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA.", DnsType.Ptr, ttl, DnsUtil.Str2DnsName("localhost"))); } }