diff --git a/README.md b/README.md index b64aaa7..6cc088c 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,12 @@ - DNSLA - CloudFlare -本系统支持多用户,每个用户可分配不同的域名解析权限;支持API接口,支持获取域名独立DNS控制面板登录链接,方便各种IDC系统对接。 +### 功能特性 + +- 多用户管理,可为每个用户可分配不同的域名解析权限 +- 提供API接口,可获取域名单独的登录链接,方便各种IDC系统对接 +- 容灾切换功能,支持ping、tcp、http(s)检测协议并自动暂停/修改域名解析,并支持邮件、微信公众号通知 +- CF优选IP功能,支持获取最新的Cloudflare优选IP,并自动更新到解析记录 ### 演示截图 @@ -29,6 +34,10 @@ ![](https://p0.meituan.net/csc/d1bd90bedca9b6cbc5da40286bdb5cd5228438.png) +CF优选IP功能,添加优选IP任务 + +![](https://p1.meituan.net/csc/da70c76753aee4bce044d16fadd56e5f217660.png) + ### 部署方法 * 从[Release](https://github.com/netcccyun/dnsmgr/releases)页面下载安装包 diff --git a/app/command/Opiptask.php b/app/command/Opiptask.php new file mode 100644 index 0000000..1a40b3c --- /dev/null +++ b/app/command/Opiptask.php @@ -0,0 +1,28 @@ +setName('opiptask') + ->setDescription('CF优选IP任务'); + } + + protected function execute(Input $input, Output $output) + { + (new OptimizeService())->execute(); + } +} diff --git a/app/controller/Dmonitor.php b/app/controller/Dmonitor.php index b287dfb..9430a43 100644 --- a/app/controller/Dmonitor.php +++ b/app/controller/Dmonitor.php @@ -157,7 +157,7 @@ class Dmonitor extends BaseController if($action == 'edit'){ $id = input('get.id/d'); $task = Db::name('dmtask')->where('id', $id)->find(); - if(empty($task)) return $this->alert('error', '任务不存在'); + if(empty($task)) return $this->alert('error', '切换策略不存在'); } $domains = []; @@ -169,7 +169,7 @@ class Dmonitor extends BaseController View::assign('info', $task); View::assign('action', $action); View::assign('support_ping', function_exists('exec')?'1':'0'); - return View::fetch('taskform'); + return View::fetch(); } public function taskinfo() @@ -177,14 +177,16 @@ class Dmonitor extends BaseController if(!checkPermission(2)) return $this->alert('error', '无权限'); $id = input('param.id/d'); $task = Db::name('dmtask')->where('id', $id)->find(); - if(empty($task)) return $this->alert('error', '任务不存在'); + if(empty($task)) return $this->alert('error', '切换策略不存在'); $switch_count = Db::name('dmlog')->where('taskid', $id)->where('date', '>=', date("Y-m-d H:i:s",strtotime("-1 days")))->count(); $fail_count = Db::name('dmlog')->where('taskid', $id)->where('date', '>=', date("Y-m-d H:i:s",strtotime("-1 days")))->where('action', 1)->count(); $task['switch_count'] = $switch_count; $task['fail_count'] = $fail_count; - if($task['type'] == 2){ + if($task['type'] == 3){ + $task['action_name'] = ['未知', '开启解析', '暂停解析']; + }elseif($task['type'] == 2){ $task['action_name'] = ['未知', '切换备用解析记录', '恢复主解析记录']; }else{ $task['action_name'] = ['未知', '暂停解析', '启用解析']; diff --git a/app/controller/Domain.php b/app/controller/Domain.php index c5f5dc4..01976f5 100644 --- a/app/controller/Domain.php +++ b/app/controller/Domain.php @@ -220,6 +220,7 @@ class Domain extends BaseController $id = input('post.id/d'); Db::name('domain')->where('id', $id)->delete(); Db::name('dmtask')->where('did', $id)->delete(); + Db::name('optimizeip')->where('did', $id)->delete(); return json(['code'=>0]); } return json(['code'=>-3]); @@ -232,9 +233,16 @@ class Domain extends BaseController $page = input('?post.page') ? input('post.page/d') : 1; $pagesize = input('?post.pagesize') ? input('post.pagesize/d') : 10; $dns = DnsHelper::getModel($aid); - $list = $dns->getDomainList($kw, $page, $pagesize); - if(!$list) return json(['code'=>-1, 'msg'=>'获取域名列表失败,'.$dns->getError()]); - return json(['code'=>0, 'data'=>$list]); + $result = $dns->getDomainList($kw, $page, $pagesize); + if(!$result) return json(['code'=>-1, 'msg'=>'获取域名列表失败,'.$dns->getError()]); + + $newlist = []; + foreach($result['list'] as $row){ + if(!Db::name('domain')->where('aid', $aid)->where('name', $row['Domain'])->find()){ + $newlist[] = $row; + } + } + return json(['code'=>0, 'data'=>['total'=>$result['total'], 'list'=>$newlist]]); } //获取解析线路和最小TTL @@ -244,10 +252,10 @@ class Domain extends BaseController if(empty($recordLine)){ $dns = DnsHelper::getModel($drow['aid'], $drow['name'], $drow['thirdid']); if(!$dns) return $this->alert('error', 'DNS模块不存在'); - $recordLine = $dns->getRecordLine($drow['name']); + $recordLine = $dns->getRecordLine(); if(!$recordLine) return $this->alert('error', '获取解析线路列表失败,'.$dns->getError()); cache('record_line_'.$drow['id'], $recordLine, 604800); - $minTTL = $dns->getMinTTL($drow['name']); + $minTTL = $dns->getMinTTL(); if($minTTL){ cache('min_ttl_'.$drow['id'], $minTTL, 604800); } diff --git a/app/controller/Index.php b/app/controller/Index.php index a904d8f..5c8a4ee 100644 --- a/app/controller/Index.php +++ b/app/controller/Index.php @@ -112,4 +112,7 @@ class Index extends BaseController return view(); } + public function test(){ + + } } diff --git a/app/controller/Optimizeip.php b/app/controller/Optimizeip.php new file mode 100644 index 0000000..8336829 --- /dev/null +++ b/app/controller/Optimizeip.php @@ -0,0 +1,174 @@ +alert('error', '无权限'); + if(request()->isPost()){ + $params = input('post.'); + foreach ($params as $key=>$value){ + if (empty($key)) { + continue; + } + config_set($key, $value); + Cache::delete('configs'); + } + return json(['code'=>0, 'msg'=>'succ']); + } + return View::fetch(); + } + + public function opiplist() + { + if(!checkPermission(2)) return $this->alert('error', '无权限'); + return View::fetch(); + } + + public function opiplist_data(){ + if(!checkPermission(2)) return json(['total'=>0, 'rows'=>[]]); + $type = input('post.type/d', 1); + $kw = input('post.kw', null, 'trim'); + $offset = input('post.offset/d'); + $limit = input('post.limit/d'); + + $select = Db::name('optimizeip')->alias('A')->join('domain B','A.did = B.id'); + if(!empty($kw)){ + if($type == 1){ + $select->whereLike('rr|B.name', '%'.$kw.'%'); + }elseif($type == 2){ + $select->whereLike('remark', '%'.$kw.'%'); + } + } + $total = $select->count(); + $list = $select->order('A.id','desc')->limit($offset, $limit)->field('A.*,B.name domain')->select(); + + return json(['total'=>$total, 'rows'=>$list]); + } + + public function opipform() + { + if(!checkPermission(2)) return $this->alert('error', '无权限'); + $action = input('param.action'); + if(request()->isPost()){ + if($action == 'add'){ + $task = [ + 'did' => input('post.did/d'), + 'rr' => input('post.rr', null, 'trim'), + 'type' => input('post.type/d'), + 'ip_type' => input('post.ip_type', null, 'trim'), + 'cdn_type' => input('post.cdn_type/d'), + 'recordnum' => input('post.recordnum/d'), + 'ttl' => input('post.ttl/d'), + 'remark' => input('post.remark', null, 'trim'), + 'addtime' => time(), + 'active' => 1 + ]; + + if(empty($task['did']) || empty($task['rr']) || empty($task['ip_type']) || empty($task['recordnum']) || empty($task['ttl'])){ + return json(['code'=>-1, 'msg'=>'必填项不能为空']); + } + if($task['recordnum'] > 5){ + return json(['code'=>-1, 'msg'=>'解析数量不能超过5个']); + } + if(Db::name('optimizeip')->where('did', $task['did'])->where('rr', $task['rr'])->find()){ + return json(['code'=>-1, 'msg'=>'当前域名的优选IP任务已存在']); + } + Db::name('optimizeip')->insert($task); + return json(['code'=>0, 'msg'=>'添加成功']); + }elseif($action == 'edit'){ + $id = input('post.id/d'); + $task = [ + 'did' => input('post.did/d'), + 'rr' => input('post.rr', null, 'trim'), + 'type' => input('post.type/d'), + 'ip_type' => input('post.ip_type', null, 'trim'), + 'cdn_type' => input('post.cdn_type/d'), + 'recordnum' => input('post.recordnum/d'), + 'ttl' => input('post.ttl/d'), + 'remark' => input('post.remark', null, 'trim'), + ]; + + if(empty($task['did']) || empty($task['rr']) || empty($task['ip_type']) || empty($task['recordnum']) || empty($task['ttl'])){ + return json(['code'=>-1, 'msg'=>'必填项不能为空']); + } + if($task['recordnum'] > 5){ + return json(['code'=>-1, 'msg'=>'解析数量不能超过5个']); + } + if(Db::name('optimizeip')->where('did', $task['did'])->where('rr', $task['rr'])->where('id', '<>', $id)->find()){ + return json(['code'=>-1, 'msg'=>'当前域名的优选IP任务已存在']); + } + Db::name('optimizeip')->where('id', $id)->update($task); + return json(['code'=>0, 'msg'=>'修改成功']); + }elseif($action == 'setactive'){ + $id = input('post.id/d'); + $active = input('post.active/d'); + Db::name('optimizeip')->where('id', $id)->update(['active'=>$active]); + return json(['code'=>0, 'msg'=>'设置成功']); + }elseif($action == 'del'){ + $id = input('post.id/d'); + Db::name('optimizeip')->where('id', $id)->delete(); + return json(['code'=>0, 'msg'=>'删除成功']); + }elseif($action == 'run'){ + $id = input('post.id/d'); + $task = Db::name('optimizeip')->where('id', $id)->find(); + if(empty($task)) return json(['code'=>-1, 'msg'=>'任务不存在']); + try{ + $result = (new OptimizeService())->execute_one($task); + Db::name('optimizeip')->where('id', $id)->update(['status' => 1, 'errmsg' => null, 'updatetime' => date('Y-m-d H:i:s')]); + return json(['code'=>0, 'msg'=>'优选任务执行成功:'.$result]); + }catch(Exception $e){ + Db::name('optimizeip')->where('id', $id)->update(['status' => 2, 'errmsg' => $e->getMessage(), 'updatetime' => date('Y-m-d H:i:s')]); + return json(['code'=>-1, 'msg'=>'优选任务执行失败:'.$e->getMessage(), 'stack'=>$e->__toString()]); + } + }else{ + return json(['code'=>-1, 'msg'=>'参数错误']); + } + } + $task = null; + if($action == 'edit'){ + $id = input('get.id/d'); + $task = Db::name('optimizeip')->where('id', $id)->find(); + if(empty($task)) return $this->alert('error', '任务不存在'); + } + + $domains = []; + foreach(Db::name('domain')->alias('A')->join('account B','A.aid = B.id')->field('A.*')->where('B.type', '<>', 'cloudflare')->select() as $row){ + $domains[$row['id']] = $row['name']; + } + View::assign('domains', $domains); + + View::assign('info', $task); + View::assign('action', $action); + return View::fetch(); + } + + public function queryapi() + { + if(!checkPermission(2)) return $this->alert('error', '无权限'); + $optimize_ip_api = input('post.optimize_ip_api/d'); + $optimize_ip_key = input('post.optimize_ip_key', null, 'trim'); + if(empty($optimize_ip_key)) return json(['code'=>-1, 'msg'=>'参数不能为空']); + try{ + $result = (new OptimizeService())->get_license($optimize_ip_api, $optimize_ip_key); + return json(['code'=>0, 'msg'=>'当前积分余额:'.$result]); + }catch(Exception $e){ + return json(['code'=>-1, 'msg'=>$e->getMessage()]); + } + } + + public function status() + { + $run_time = Db::name('optimizeip')->where('active', 1)->order('updatetime', 'desc')->value('updatetime'); + $run_state = $run_time ? (time()-strtotime($run_time) > 3600 ? 0 : 1) : 0; + return $run_state == 1 ? 'ok' : 'error'; + } +} \ No newline at end of file diff --git a/app/lib/OptimizeService.php b/app/lib/OptimizeService.php new file mode 100644 index 0000000..1f125b9 --- /dev/null +++ b/app/lib/OptimizeService.php @@ -0,0 +1,204 @@ + ['DEF'=>'default', 'CT'=>'telecom', 'CU'=>'unicom', 'CM'=>'mobile', 'AB'=>'oversea'], + 'dnspod' => ['DEF'=>'0', 'CT'=>'10=0', 'CU'=>'10=1', 'CM'=>'10=3', 'AB'=>'3=0'], + 'huawei' => ['DEF'=>'default_view', 'CT'=>'Dianxin', 'CU'=>'Liantong', 'CM'=>'Yidong', 'AB'=>'Abroad'], + 'west' => ['DEF'=>'', 'CT'=>'LTEL', 'CU'=>'LCNC', 'CM'=>'LMOB', 'AB'=>'LFOR'], + 'dnsla' => ['DEF'=>'', 'CT'=>'84613316902921216', 'CU'=>'84613316923892736', 'CM'=>'84613316953252864', 'AB'=>''], + ]; + + private $ip_address = []; + private $add_num = 0; + private $change_num = 0; + private $del_num = 0; + + public static function get_license($api, $key){ + if($api == 1){ + $url = 'https://api.hostmonit.com/get_license?license='.$key; + }else{ + $url = 'https://monitor.gacjie.cn/api/client/get_account_integral?license='.$key; + } + $response = get_curl($url); + $arr = json_decode($response, true); + if(isset($arr['code']) && $arr['code'] == 200 && isset($arr['count'])){ + return $arr['count']; + }elseif(isset($arr['info'])){ + throw new Exception('获取剩余请求次数失败,'.$arr['info']); + }else{ + throw new Exception('获取剩余请求次数失败'); + } + } + + public function get_ip_address($cdn_type = 1, $ip_type = 'v4'){ + $api = config_get('optimize_ip_api', 0); + if($api == 1){ + $url = 'https://api.hostmonit.com/get_optimization_ip'; + }else{ + $url = 'https://monitor.gacjie.cn/api/client/get_ip_address'; + } + $params = [ + 'key' => config_get('optimize_ip_key', 'o1zrmHAF'), + 'type' => $ip_type, + ]; + if($api == 0){ + $params['cdn_server'] = $cdn_type; + } + $response = get_curl($url, json_encode($params), 0, 0, 0, 0, 0, ['Content-Type: application/json; charset=UTF-8']); + $arr = json_decode($response, true); + if(isset($arr['code']) && $arr['code'] == 200){ + return $arr['info']; + }elseif(isset($arr['info'])){ + throw new Exception('获取优选IP数据失败,'.$arr['info']); + }elseif(isset($arr['msg'])){ + throw new Exception('获取优选IP数据失败,'.$arr['msg']); + }else{ + throw new Exception('获取优选IP数据失败,原因未知'); + } + } + + public function get_ip_address2($cdn_type = 1, $ip_type = 'v4'){ + $key = $cdn_type.'_'.$ip_type; + if(!isset($this->ip_address[$key])){ + $info = $this->get_ip_address($cdn_type, $ip_type); + $res = []; + if(isset($info['DEF'])) $res['DEF'] = $info['DEF']; + if(isset($info['CT'])) $res['CT'] = $info['CT']; + if(isset($info['CU'])) $res['CU'] = $info['CU']; + if(isset($info['CM'])) $res['CM'] = $info['CM']; + $this->ip_address[$key] = $res; + } + return $this->ip_address[$key]; + } + + //批量执行优选任务 + public function execute(){ + $list = Db::name('optimizeip')->where('active', 1)->select(); + echo '开始执行IP优选任务,共获取到'.count($list).'个待执行任务'."\n"; + foreach($list as $row){ + try{ + $result = $this->execute_one($row); + Db::name('optimizeip')->where('id', $row['id'])->update(['status' => 1, 'errmsg' => null, 'updatetime' => date('Y-m-d H:i:s')]); + echo '优选任务'.$row['id'].'执行成功:'.$result."\n"; + }catch(Exception $e){ + Db::name('optimizeip')->where('id', $row['id'])->update(['status' => 2, 'errmsg' => $e->getMessage(), 'updatetime' => date('Y-m-d H:i:s')]); + echo '优选任务'.$row['id'].'执行失败:'.$e->getMessage()."\n"; + } + } + } + + //执行单个优选任务 + public function execute_one($row){ + $this->add_num = 0; + $this->change_num = 0; + $this->del_num = 0; + $ip_types = explode(',', $row['ip_type']); + foreach($ip_types as $ip_type){ + if(empty($ip_type)) continue; + + $drow = Db::name('domain')->alias('A')->join('account B','A.aid = B.id')->where('A.id', $row['did'])->field('A.*,B.type,B.ak,B.sk,B.ext')->find(); + if(!$drow){ + throw new Exception('域名不存在(ID:'.$row['did'].')'); + } + if(!isset(self::$line_name[$drow['type']])){ + throw new Exception('不支持的DNS服务商'); + } + + $info = $this->get_ip_address2($row['cdn_type'], $ip_type); + + $dns = DnsHelper::getModel($drow['aid'], $drow['name'], $drow['thirdid']); + $domainRecords = $dns->getSubDomainRecords($row['rr'], 1, 100); + if(!$domainRecords){ + throw new Exception('获取记录列表失败,'.$dns->getError()); + } + + if($row['type'] == 1 && isset($info['DEF']) && !empty($info['DEF'])) $row['type'] = 0; + + foreach($info as $line=>$iplist){ + if(empty($iplist)) continue; + $get_ips = array_column($iplist, 'ip'); + if($drow['type']=='huawei') {sort($get_ips); $get_ips = [implode(',',$get_ips)]; $row['recordnum'] = 1;} + if($row['type'] == 1 && $line == 'CT') $line = 'DEF'; + $line_name = self::$line_name[$drow['type']][$line]; + $this->process_dns_line($dns, $row, $domainRecords['list'], $get_ips, $line_name, $ip_type); + } + } + + return '成功添加'.$this->add_num.'条记录,修改'.$this->change_num.'条记录,删除'.$this->del_num.'条记录'; + } + + //处理单个线路的解析记录 + private function process_dns_line($dns, $row, $record_list, $get_ips, $line_name, $ip_type){ + $record_num = $row['recordnum']; + $records = array_filter($record_list, function($v) use($line_name){ + return $v['Line'] == $line_name; + }); + + //删除CNAME记录 + $cname_records = array_filter($records, function($v){ + return $v['Type'] == 'CNAME'; + }); + if(!empty($cname_records)){ + foreach($cname_records as $record){ + $dns->deleteDomainRecord($record['RecordId']); + } + } + + //处理A/AAAA记录 + $ip_records = array_filter($records, function($v) use ($ip_type){ + return $v['Type'] == ($ip_type == 'v6' ? 'AAAA' : 'A'); + }); + + if(!empty($ip_records) && is_array($ip_records[array_key_first($ip_records)]['Value'])){ //处理华为云记录 + foreach($ip_records as &$ip_record){ + sort($ip_record['Value']); + $ip_record['Value'] = implode(',', $ip_record['Value']); + } + } + + $exist_ips = array_column($ip_records, 'Value'); + $add_ips = array_diff($get_ips, $exist_ips); + $del_ips = array_diff($exist_ips, $get_ips); + $correct_ips = array_diff($exist_ips, $del_ips); + $correct_count = count($correct_ips); + if(!empty($del_ips)){ + foreach($ip_records as $record){ + if(in_array($record['Value'], $del_ips)){ + $add_ip = array_pop($add_ips); + if($add_ip){ + $res = $dns->updateDomainRecord($record['RecordId'], $row['rr'], $ip_type == 'v6' ? 'AAAA' : 'A', $add_ip, $line_name, $row['ttl']); + if(!$res){ + throw new Exception('修改解析失败,'.$dns->getError()); + } + $this->change_num++; + $correct_count++; + }else{ + $res = $dns->deleteDomainRecord($record['RecordId']); + if(!$res){ + throw new Exception('删除解析失败,'.$dns->getError()); + } + $this->del_num++; + } + } + } + } + if($correct_count < $record_num && !empty($add_ips)){ + foreach($add_ips as $add_ip){ + $res = $dns->addDomainRecord($row['rr'], $ip_type == 'v6' ? 'AAAA' : 'A', $add_ip, $line_name, $row['ttl']); + if(!$res){ + throw new Exception('添加解析失败,'.$dns->getError()); + } + $this->add_num++; + $correct_count++; + if($correct_count >= $record_num) break; + } + } + } +} \ No newline at end of file diff --git a/app/lib/TaskRunner.php b/app/lib/TaskRunner.php index f6e4cbd..7925bc8 100644 --- a/app/lib/TaskRunner.php +++ b/app/lib/TaskRunner.php @@ -27,31 +27,43 @@ class TaskRunner public function execute($row) { - if($row['checktype'] == 2){ - $result = CheckUtils::curl($row['checkurl'], $row['timeout'], $row['main_value']); - }else if($row['checktype'] == 1){ - $result = CheckUtils::tcp($row['main_value'], $row['tcpport'], $row['timeout']); - }else{ - $result = CheckUtils::ping($row['main_value']); - } - - $action = 0; - if($result['status'] && $row['status']==1){ - if($row['cycle'] <= 1 || $row['errcount'] >= $row['cycle']){ - $this->db()->name('dmtask')->where('id', $row['id'])->update(['status'=>0, 'errcount'=>0, 'switchtime'=>time()]); + if($row['type'] == 3){ //条件开启解析 + $action = 0; + $remain = $this->db()->name('dmtask')->where(['did'=>$row['did'], 'rr'=>$row['rr'], 'type'=>1, 'status'=>0])->count(); + if($remain<=$row['cycle'] && $row['status']==0){ $action = 2; - }else{ - $this->db()->name('dmtask')->where('id', $row['id'])->inc('errcount')->update(); - } - }elseif(!$result['status'] && $row['status']==0){ - if($row['cycle'] <= 1 || $row['errcount'] >= $row['cycle']){ $this->db()->name('dmtask')->where('id', $row['id'])->update(['status'=>1, 'errcount'=>0, 'switchtime'=>time()]); + }elseif($remain>$row['cycle'] && $row['status']==1){ $action = 1; + $this->db()->name('dmtask')->where('id', $row['id'])->update(['status'=>0, 'errcount'=>0, 'switchtime'=>time()]); + } + }else{ + if($row['checktype'] == 2){ + $result = CheckUtils::curl($row['checkurl'], $row['timeout'], $row['main_value']); + }else if($row['checktype'] == 1){ + $result = CheckUtils::tcp($row['main_value'], $row['tcpport'], $row['timeout']); }else{ - $this->db()->name('dmtask')->where('id', $row['id'])->inc('errcount')->update(); + $result = CheckUtils::ping($row['main_value']); + } + + $action = 0; + if($result['status'] && $row['status']==1){ + if($row['cycle'] <= 1 || $row['errcount'] >= $row['cycle']){ + $this->db()->name('dmtask')->where('id', $row['id'])->update(['status'=>0, 'errcount'=>0, 'switchtime'=>time()]); + $action = 2; + }else{ + $this->db()->name('dmtask')->where('id', $row['id'])->inc('errcount')->update(); + } + }elseif(!$result['status'] && $row['status']==0){ + if($row['cycle'] <= 1 || $row['errcount'] >= $row['cycle']){ + $this->db()->name('dmtask')->where('id', $row['id'])->update(['status'=>1, 'errcount'=>0, 'switchtime'=>time()]); + $action = 1; + }else{ + $this->db()->name('dmtask')->where('id', $row['id'])->inc('errcount')->update(); + } + }elseif($row['errcount'] > 0){ + $this->db()->name('dmtask')->where('id', $row['id'])->update(['errcount'=>0]); } - }elseif($row['errcount'] > 0){ - $this->db()->name('dmtask')->where('id', $row['id'])->update(['errcount'=>0]); } if($action > 0){ @@ -71,7 +83,7 @@ class TaskRunner if(!$res){ $this->db()->name('log')->insert(['uid' => 0, 'domain' => $drow['name'], 'action' => '修改解析失败', 'data' => $dns->getError(), 'addtime' => date("Y-m-d H:i:s")]); } - }elseif($row['type'] == 1){ + }elseif($row['type'] == 1 || $row['type'] == 3){ $dns = DnsHelper::getModel2($drow); $res = $dns->setDomainRecordStatus($row['recordid'], '0'); if(!$res){ @@ -86,7 +98,7 @@ class TaskRunner if(!$res){ $this->db()->name('log')->insert(['uid' => 0, 'domain' => $drow['name'], 'action' => '修改解析失败', 'data' => $dns->getError(), 'addtime' => date("Y-m-d H:i:s")]); } - }elseif($row['type'] == 1){ + }elseif($row['type'] == 1 || $row['type'] == 3){ $dns = DnsHelper::getModel2($drow); $res = $dns->setDomainRecordStatus($row['recordid'], '1'); if(!$res){ @@ -101,11 +113,13 @@ class TaskRunner $this->db()->name('dmlog')->insert([ 'taskid' => $row['id'], 'action' => $action, - 'errmsg' => $result['status'] ? null : $result['errmsg'], + 'errmsg' => isset($result) ? ($result['status'] ? null : $result['errmsg']) : null, 'date' => date('Y-m-d H:i:s') ]); $this->closeDb(); - MsgNotice::send($action, $row, $result); + if($row['type'] != 3){ + MsgNotice::send($action, $row, $result); + } } } \ No newline at end of file diff --git a/app/lib/dns/dnspod.php b/app/lib/dns/dnspod.php index 0049b3e..945ef35 100644 --- a/app/lib/dns/dnspod.php +++ b/app/lib/dns/dnspod.php @@ -84,6 +84,8 @@ class dnspod implements DnsInterface { ]; } return ['total' => $data['RecordCountInfo']['TotalCount'], 'list' => $list]; + }elseif($this->error == '记录列表为空。'){ + return ['total' => 0, 'list' => []]; } return false; } diff --git a/app/lib/dns/huawei.php b/app/lib/dns/huawei.php index 781c428..148dd57 100644 --- a/app/lib/dns/huawei.php +++ b/app/lib/dns/huawei.php @@ -91,6 +91,7 @@ class huawei implements DnsInterface { public function getDomainRecordInfo($RecordId){ $data = $this->send_reuqest('GET', '/v2.1/zones/'.$this->domainid.'/recordsets/'.$RecordId); if($data){ + if($data['name'] == $data['zone_name']) $data['name'] = '@'; return [ 'RecordId' => $data['id'], 'Domain' => rtrim($data['zone_name'], '.'), diff --git a/app/sql/install.sql b/app/sql/install.sql index bc0a520..b1291d8 100644 --- a/app/sql/install.sql +++ b/app/sql/install.sql @@ -5,7 +5,7 @@ CREATE TABLE `dnsmgr_config` ( PRIMARY KEY (`key`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -INSERT INTO `dnsmgr_config` VALUES ('version', '1003'); +INSERT INTO `dnsmgr_config` VALUES ('version', '1005'); INSERT INTO `dnsmgr_config` VALUES ('notice_mail', '0'); INSERT INTO `dnsmgr_config` VALUES ('notice_wxtpl', '0'); INSERT INTO `dnsmgr_config` VALUES ('mail_smtp', 'smtp.qq.com'); @@ -64,7 +64,7 @@ CREATE TABLE `dnsmgr_permission` ( DROP TABLE IF EXISTS `dnsmgr_log`; CREATE TABLE `dnsmgr_log` ( - `id` int(11) NOT NULL AUTO_INCREMENT, + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `uid` int(11) unsigned NOT NULL, `action` varchar(40) NOT NULL, `domain` varchar(128) NOT NULL DEFAULT '', @@ -77,7 +77,7 @@ CREATE TABLE `dnsmgr_log` ( DROP TABLE IF EXISTS `dnsmgr_dmtask`; CREATE TABLE `dnsmgr_dmtask` ( - `id` int(11) NOT NULL AUTO_INCREMENT, + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `did` int(11) unsigned NOT NULL, `rr` varchar(128) NOT NULL, `recordid` varchar(60) NOT NULL, @@ -105,7 +105,7 @@ CREATE TABLE `dnsmgr_dmtask` ( DROP TABLE IF EXISTS `dnsmgr_dmlog`; CREATE TABLE `dnsmgr_dmlog` ( - `id` int(11) NOT NULL AUTO_INCREMENT, + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `taskid` int(11) unsigned NOT NULL, `action` tinyint(4) NOT NULL DEFAULT 0, `errmsg` varchar(100) DEFAULT NULL, @@ -113,4 +113,24 @@ CREATE TABLE `dnsmgr_dmlog` ( PRIMARY KEY (`id`), KEY `taskid` (`taskid`), KEY `date` (`date`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +DROP TABLE IF EXISTS `dnsmgr_optimizeip`; +CREATE TABLE `dnsmgr_optimizeip` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `did` int(11) unsigned NOT NULL, + `rr` varchar(128) NOT NULL, + `type` tinyint(1) NOT NULL DEFAULT 0, + `ip_type` varchar(10) NOT NULL, + `cdn_type` tinyint(5) NOT NULL DEFAULT 1, + `recordnum` tinyint(5) NOT NULL DEFAULT 2, + `ttl` int(5) NOT NULL DEFAULT 600, + `remark` varchar(100) DEFAULT NULL, + `addtime` datetime NOT NULL, + `updatetime` datetime DEFAULT NULL, + `status` tinyint(1) NOT NULL DEFAULT 0, + `active` tinyint(1) NOT NULL DEFAULT 0, + `errmsg` varchar(100) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `did` (`did`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; \ No newline at end of file diff --git a/app/sql/update.sql b/app/sql/update.sql index 65aae20..1ab9e5d 100644 --- a/app/sql/update.sql +++ b/app/sql/update.sql @@ -5,7 +5,7 @@ CREATE TABLE IF NOT EXISTS `dnsmgr_config` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE IF NOT EXISTS `dnsmgr_dmtask` ( - `id` int(11) NOT NULL AUTO_INCREMENT, + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `did` int(11) unsigned NOT NULL, `rr` varchar(128) NOT NULL, `recordid` varchar(60) NOT NULL, @@ -32,7 +32,7 @@ CREATE TABLE IF NOT EXISTS `dnsmgr_dmtask` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE IF NOT EXISTS `dnsmgr_dmlog` ( - `id` int(11) NOT NULL AUTO_INCREMENT, + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `taskid` int(11) unsigned NOT NULL, `action` tinyint(4) NOT NULL DEFAULT 0, `errmsg` varchar(100) DEFAULT NULL, @@ -40,4 +40,23 @@ CREATE TABLE IF NOT EXISTS `dnsmgr_dmlog` ( PRIMARY KEY (`id`), KEY `taskid` (`taskid`), KEY `date` (`date`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE IF NOT EXISTS `dnsmgr_optimizeip` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `did` int(11) unsigned NOT NULL, + `rr` varchar(128) NOT NULL, + `type` tinyint(1) NOT NULL DEFAULT 0, + `ip_type` varchar(10) NOT NULL, + `cdn_type` tinyint(5) NOT NULL DEFAULT 1, + `recordnum` tinyint(5) NOT NULL DEFAULT 2, + `ttl` int(5) NOT NULL DEFAULT 600, + `remark` varchar(100) DEFAULT NULL, + `addtime` datetime NOT NULL, + `updatetime` datetime DEFAULT NULL, + `status` tinyint(1) NOT NULL DEFAULT 0, + `active` tinyint(1) NOT NULL DEFAULT 0, + `errmsg` varchar(100) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `did` (`did`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; \ No newline at end of file diff --git a/app/view/common/layout.html b/app/view/common/layout.html index 1f9162e..f371b62 100644 --- a/app/view/common/layout.html +++ b/app/view/common/layout.html @@ -121,6 +121,19 @@
由于CloudFlare官方IP是泛播路由,同一个IP在不同地区不同运营商所链接的机房是不同的,速度或延迟也会有区别。目前网上也有很多CF优选CNAME服务,然而公共的CNAME可能无法满足稳定性和安全性的需要。
+本功能可以获取CloudFlare最新的优选IP地址(分为电信/联通/移动线路),并自动更新到域名解析记录。
+cd {:app()->getRootPath()} && php think opiptask