最近做的一个产品中有个需求,就是客户使用的时候可以通过Web网页修改服务器的IP地址(客户是普通使用者,没有Linux使用经验,我们的产品作为一台服务器部署到客户机房,客户通过HTTP方式访问使用)。
在Linux中一切皆是文件,修改IP地址同样是只要修改了对应网卡的配置文件后重启网络服务,只要配置正确无IP冲突,即可成功启用新的IP地址。
所以我们实现的思路是访问网卡配置文件,获取当前网卡的配置信息展示(如果有多个网卡就展示多个网卡信息,用tab来切换网卡信息),然后用户可以修改对应的网卡网络信息提交保存,后台通过修改网卡对应的文件内容,即可达到修改网卡IP地址的功能。
当然因为要访问修改网卡配置文件和执行重启网络的命令,对Web的权限有一定的要求,因为客户是内网运行,简单粗暴的使用了root用户来启动Web程序。
以下代码实现了ASP.NET Core修改CentOS的IP地址功能。
前端使用的是LayUI
1 @model viewmodel.IPVm 2 @{ 3 var ipList = Model.IpList; 4 } 5 6 <div class="layui-bg-gray" style="padding: 30px;"> 7 ="layui-row layui-col-space15" 8 ="layui-col-md6" 9 ="layui-card"="min-height: 280px;" 10 ="layui-card-header" 11 配置服务器IP 12 </div 13 ="layui-card-body" 14 ="layui-tab-item layui-show" id="tbcontent_0" lay-filter="tbcontent_0filter" 15 @{ 16 17 if (ipList != null && ipList.Any()) 18 { 19 ul ="layui-tab-title" 20 21 @{ 22 for (int i = 0; i ipList.Count; i++) 23 { 24 var ip = ipList[i]; 25 <li>@ip.IpNameli 26 } 27 } 28 ul 29 30 ="layui-tab-content" 31 @{ 32 for (int i = 0; i 33 34 35 var i1 = i; 36 <div class="layui-tab-item"="tbcontent_@i"="tbcontent_1filter" 37 38 ="layui-form-item layui-form"="Ipv4div_@i1" 39 label for="Ipv4div_@i1" class="layui-form-label"="width: 100px">IPv4地址:label 40 ="layui-input-block"="margin-left: 130px" 41 input autocomplete="off" type="text" name="Ipv4div_txt_@i1" value="@ip.Ipv4" maxlength="15" placeholder="请填写IPv4的IP地址"="layui-input"="Ipv4div_txt_@i1" 42 43 44 ="IpMaskdiv_@i1" 45 ="IpMaskdiv_@i1">子网掩码: 46 47 ="IpMaskdiv_txt_@i1"="@ip.IpMask"="请填写IPv4的子网掩码"="IpMaskdiv_txt_@i1" 48 49 50 ="IpGetWaydiv_@i1" 51 ="IpGetWaydiv_@i1">网关地址: 52 53 ="IpGetWay_txt_@i1"="@ip.IpGetWay"="请填写IPv4的网关地址"="IpGetWay_txt_@i1" 54 55 56 ="IpDnsdiv_@i1" 57 ="IpDnsdiv_@i1">DNS地址: 58 59 ="IpDnsdiv_txt_@i1"="@ip.IpDns"="请填写IPv4的DNS地址"="IpDnsdiv_txt_@i1" 60 61 62 type="hidden"="@ip.IpGuid"="32"="IpGuid_@i1"="IpGuid_@i1" /> 63 ="@ip.IpName"="IpName_@i1"="IpName_@i1" 64 button onclick="SaveIpConfig(this);"="button"="layui-btn"="btn_@i"="btn_@i filter">提交修改button 65 66 67 68 69 } 70 } 71 72 73 74 75 76 77 script ="text/javascript" 78 var element = layui.element; 79 layui.use('layer); 80 81 function SaveIpConfig(e) { 82 btnId $(e).attr(id 83 84 if (btnId == '' ||== undefined) return; 85 86 id btnId.split(_ 87 88 (id.length != 2) 89 90 ip $("#Ipv4div_txt_" + id[1]).val(); 91 mask #IpMaskdiv_txt_ 92 getWay #IpGetWay_txt_ 93 dns #IpDnsdiv_txt_ 94 nid #IpGuid_ 95 ipName #IpName_ 96 97 ($.trim(ip) '') { 98 layer.alert(请填写IP地址, 99 { 100 title: 错误' 101 }); 102 103 } else { 104 (!validateIP($.trim(ip))) { 105 layer.alert(IP地址格式不正确106 { 107 title: 108 }); 109 110 } 111 } 112 113 (mask.trim() 114 请填写子网掩码115 title: 116 }); 117 118 119 validateIP($.trim(mask))) { 120 子网掩码格式不正确121 122 123 124 125 126 127 128 ($.trim(getWay) && validateIP($.trim(getWay))) { 129 网关地址格式不正确130 131 132 133 134 135 ($.trim(dns) validateIP($.trim(dns))) { 136 DNS格式不正确137 138 139 140 141 142 layer.confirm(确定要修改服务器IP吗?!143 { icon: 3信息 },1)">144 (index) { 145 layer.close(index); 146 index layer.load(0147 $.ajax({ 148 type: POST149 url: /ChangeIp/SaveIpConfig150 data: { ip: ip,mask: mask,getWay: getWay,dns: dns,nid: nid,ipName: ipName},1)">151 dataType: json152 success: (result) { 153 (result && result undefined154 (result.code 200155 layer.alert(result.msg,1)">156 { 157 title: 158 }); 159 160 } 161 layer.alert(修改成功,请3秒后访问新的IP地址来使用系统。162 163 成功164 165 166 167 168 layer.alert(返回数据错误。169 title: 170 }); 171 172 },1)">173 complete: (xhr,ts) { 174 layer.close(index); 175 } 176 177 return false178 179 } 180 validateIP(str) { 181 re = /^(?:(?:2[0-4][0-9]\.)|(?:25[0-5]\.)|(?:1[0-9][0-9]\.)|(?:[1-9][0-9]\.)|(?:[0-9]\.)){3}(?:(?:2[0-4][0-9])|(?:25[0-5])|(?:1[0-9][0-9])|(?:[1-9][0-9])|(?:[0-9]))$182 re.test(str); 183 184 script>
后台VM实体
1 namespace viewmodel 2 { 3 public IPVm 4 { 3 /// <summary> 4 /// 本地IP地址 5 </summary> 6 public List<IpModel> IpList { get; set; } 7 8 }
IpModel实体
Model { <summary> 获取本地IP地址信息 </summary> IpModel { <summary> IP配置文件路径 </summary> string IpConfigFile { ; } 名称 string IpName { 一个随机编号 string IpGuid { IPv4的地址 string Ipv4 { IPv6的地址 string Ipv6 { 子网掩码 string IpMask { 网关地址 string IpGetWay { DNS地址 string IpDns { ; } } }
using Microsoft.AspNetCore.Mvc; Microsoft.Extensions.Logging; MidSoft.Sfrz.Model; System; 5 System.Collections.Generic; System.Diagnostics; 7 System.IO; 8 System.Linq; 9 System.Net; 10 System.Net.NetworkInformation; System.Threading.Tasks; 12 13 Controllers 14 15 ChangeIpController : Controller 16 { 17 private readonly ILogger<CshSjkController> _logger; 18 public ChangeIpController( ILogger<CshSjkController> logger) 19 { 20 _logger = logger; 22 23 public IActionResult Index() 24 25 #region 获取IP地址 26 27 var IpList = new List<IpModel>(); 28 try 29 { 30 var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces(); 31 foreach (var nic in networkInterfaces) 32 33 if (string.Equals("loopback",nic.Name) || locontinue 34 35 var ipModel = new IpModel(); 36 37 var file = Path.Combine(/etcsysconfignetwork-scriptsifcfg-{nic.Name}");//这里是网卡的配置文件名称,可能每台服务器的开头不一样,比如我这里的网卡都是ifcfg-开头的文件,记得确认一下 38 39 ipModel.IpConfigFile = file; 40 41 ipModel.IpDns = "" 42 ipModel.IpGetWay = 43 ipModel.IpMask = 44 ipModel.Ipv4 = 45 ipModel.Ipv6 = 46 ipModel.IpName = nic.Name; 47 ipModel.IpGuid = Guid.NewGuid().ToString(D 48 49 if (System.IO.File.Exists(file)) 50 51 var ipDictionary = new Dictionary<string,string> 52 #if DEBUG 53 _logger.LogInformation(==========IP============ 54 _logger.LogInformation($FilePath={file} 55 #endif 56 57 using (var streamReader = StreamReader(file)) 58 { 59 var line = string.Empty; 60 while ((line = streamReader.ReadLine()) != null) 61 { 62 var split = line.Split('=' 63 if (split.Length > 1 64 { 65 ipDictionary.Add(split[0],split[]); } 68 70 _logger.LogInformation($DicLength:{ipDictionary.Count} 71 _logger.LogInformation(==========IPEnd============ 72 73 (ipDictionary.Any()) 74 75 if (ipDictionary.ContainsKey(NAME")) ipModel.IpName = ipDictionary["].Replace(\" 76 UUID")) ipModel.IpGuid = ipDictionary[ 77 IPADDR")) ipModel.Ipv4 = ipDictionary[ 78 PREFIX)) 79 80 int.TryParse(ipDictionary[""),1)">out var ipMask); 81 ipMask = Math.Abs(ipMask); 82 if (ipMask == 0 || ipMask > 32 83 84 ipModel.IpMask = 255.255.255.0 85 86 else 87 88 var ip = Int2IpMask(ipMask); 89 ipModel.IpMask = ${ip.Item1}.{ip.Item2}.{ip.Item3}.{ip.Item4} 90 91 92 93 GATEWAY")) ipModel.IpGetWay = ipDictionary[ 94 DNS1")) ipModel.IpDns = ipDictionary[ 95 DNS2 96 97 98 99 100 IpList.Add(ipModel); 101 } 102 103 catch (Exception e) 104 105 _logger.LogError($加载IP地址配置文件时出错:{e}106 107 108 109 #endregion 110 111 return View(IpList); 112 113 114 #region 保存服务器网卡IP配置 115 116 保存服务器网卡IP配置 117 118 <returns></returns> 119 [HttpPost] 120 121 async Task<JsonResult> SaveIpConfig() 122 123 var ip = Request.Form[ip]; 124 var mask = Request.Form[mask125 var getWay = Request.Form[getWay126 var dns = Request.Form[dns127 var nid = Request.Form[nid128 var ipName = Request.Form[ipName129 130 .IsNullOrWhiteSpace(ip)) 131 132 return new JsonResult(new { code = 300请填写IP地址 }); 133 134 if (!IPAddress.TryParse(ip,1)">out _)) 135 136 IP地址格式不正确137 138 if (!IPAddress.TryParse(mask,1)">139 140 子网掩码地址格式不正确141 142 143 string.IsNullOrEmpty(mask) || mask.ToString().Split(.').Length != 4144 145 146 147 148 var ips = mask.ToString().Split(149 150 var ipMask = 0151 var ip1 = Ip2Mask(ips[152 var ip2 = Ip2Mask(ips[153 var ip3 = Ip2Mask(ips[2154 var ip4 = Ip2Mask(ips[3155 if (ip1 == null|| ip2 == null|| ip3 == null|| ip4 == 156 157 子网掩码填写不正确158 159 160 ipMask = (int)ip1 + (int)ip2 + (int)ip3 + (int)ip4; 161 162 163 164 165 166 167 if (!string.IsNullOrWhiteSpace(getWay) && !IPAddress.TryParse(ip,1)">168 169 网关地址格式不正确170 171 172 string.IsNullOrWhiteSpace(dns) && !IPAddress.TryParse(dns,1)">173 174 DNS格式不正确175 176 177 .IsNullOrWhiteSpace(ipName)) 178 179 ipName = enp1s0180 181 .IsNullOrWhiteSpace(nid)) 182 183 nid = Guid.NewGuid().ToString(185 186 Task.Run(async () => 187 188 189 ifcfg-{ipName}190 await Task.Delay(200191 192 193 var fileStream = FileStream(file,FileMode.Create)) 194 195 var fileStreamWriter = StreamWriter(fileStream)) 196 197 await fileStreamWriter.WriteLineAsync(@"TYPE=""Ethernet""198 PROXY_METHOD=""none""199 BROWSER_ONLY=""no""200 BOOTPROTO=""none""201 DEFROUTE=""yes""202 IPV4_FAILURE_FATAL=""no""203 IPV6INIT=""yes""204 IPV6_AUTOCONF=""yes""205 IPV6_DEFROUTE=""yes""206 IPV6_FAILURE_FATAL=""no""207 IPV6_ADDR_GEN_MODE=""stable-privacy""208 await fileStreamWriter.WriteLineAsync($NAME=""{ipName}""209 UUID=""{nid}""210 DEVICE=""{ipName}""211 ONBOOT=""yes""212 IPADDR=""{ip}""213 PREFIX=""{ipMask}""214 GATEWAY=""{getWay}""215 DNS1=""{dns}""216 IPV6_PRIVACY=""no""217 218 219 220 await Process.Start(service network restart")?.WaitForExitAsync()!221 222 223 224 _logger.LogError($修改服务器IP地址出错:{e}225 226 227 228 200229 230 231 232 233 #region 子网掩码位数转子网掩码IP 234 235 private Tuple<int,1)">int> Int2IpMask( ipLength) 236 237 int ip1 = 0,ip2 = 238 var tmpvar = ipLength; 239 if (tmpvar > 32 || tmpvar < 240 241 242 243 244 if (tmpvar >= 8245 246 ip1 = 255247 tmpvar -= 248 249 250 251 ip1 = Int2BitMask(tmpvar); 252 new Tuple<int>(ip1,1)">253 254 255 256 ip2 = 257 tmpvar -= 258 259 260 261 ip2 =262 263 264 265 266 ip3 = 267 tmpvar -= 268 269 270 271 ip3 =272 273 274 ip4 =275 int>(ip1,ip4); 276 277 278 int Int2BitMask( num) 279 280 if (num >= 281 282 return (283 284 var pianyiliang = 0xff00285 while (num > 286 287 pianyiliang = pianyiliang >> 288 num--289 290 return (pianyiliang & 0xff291 292 293 294 #region 子网掩码IP地址转位数 295 int? Ip2Mask( ip) 296 297 int.TryParse(ip,1)"> num); 298 if (num == 299 300 return 301 302 303 var i = 304 while (i < 305 306 if (num == (pianyiliang & 307 308 i; 309 310 pianyiliang >>= 311 i++312 313 314 315 316 317 }