ASP.NET Core修改CentOS的IP地址


最近做的一个产品中有个需求,就是客户使用的时候可以通过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     <div class="layui-row layui-col-space15">
  8         <div class="layui-col-md6">
  9             <div class="layui-card" style="min-height: 280px;">
 10                 <div class="layui-card-header">
 11                     配置服务器IP
 12                 div>
 13                 <div class="layui-card-body">
 14                     <div class="layui-tab-item layui-show" id="tbcontent_0" lay-filter="tbcontent_0filter">
 15                         @{
 16 
 17                             if (ipList != null && ipList.Any())
 18                             { 
 19                                     <ul class="layui-tab-title">
 20 
 21                                         @{
 22                                         for (int i = 0; i < ipList.Count; i++)
 23                                         {
 24                                             var ip = ipList[i];
 25                                             >@ip.IpNameli>
 26                                         }
 27                                     }
 28                                     ul>
 29                       
 30                                 <div class="layui-tab-content">
 31                                     @{
 32                                         for (int i = 0; i < ipList.Count; i++)
 33                                         {
 34                                             var ip = ipList[i];
 35                                             var i1 = i;
 36                                             
="layui-tab-item" id="tbcontent_@i" lay-filter="tbcontent_1filter"> 37 38 <div class="layui-form-item layui-form" lay-filter="Ipv4div_@i1"> 39 <label for="Ipv4div_@i1" class="layui-form-label" style="width: 100px">IPv4地址:label> 40 <div class="layui-input-block" style="margin-left: 130px"> 41 <input autocomplete="off" type="text" name="Ipv4div_txt_@i1" value="@ip.Ipv4" maxlength="15" placeholder="请填写IPv4的IP地址" class="layui-input" id="Ipv4div_txt_@i1"> 42 div> 43 div> 44 <div class="layui-form-item layui-form" lay-filter="IpMaskdiv_@i1"> 45 <label for="IpMaskdiv_@i1" class="layui-form-label" style="width: 100px">子网掩码:label> 46 <div class="layui-input-block" style="margin-left: 130px"> 47 <input autocomplete="off" type="text" name="IpMaskdiv_txt_@i1" value="@ip.IpMask" maxlength="15" placeholder="请填写IPv4的子网掩码" class="layui-input" id="IpMaskdiv_txt_@i1"> 48 div> 49 div> 50 <div class="layui-form-item layui-form" lay-filter="IpGetWaydiv_@i1"> 51 <label for="IpGetWaydiv_@i1" class="layui-form-label" style="width: 100px">网关地址:label> 52 <div class="layui-input-block" style="margin-left: 130px"> 53 <input autocomplete="off" type="text" name="IpGetWay_txt_@i1" value="@ip.IpGetWay" maxlength="15" placeholder="请填写IPv4的网关地址" class="layui-input" id="IpGetWay_txt_@i1"> 54 div> 55 div> 56 <div class="layui-form-item layui-form" lay-filter="IpDnsdiv_@i1"> 57 <label for="IpDnsdiv_@i1" class="layui-form-label" style="width: 100px">DNS地址:label> 58 <div class="layui-input-block" style="margin-left: 130px"> 59 <input autocomplete="off" type="text" name="IpDnsdiv_txt_@i1" value="@ip.IpDns" maxlength="15" placeholder="请填写IPv4的DNS地址" class="layui-input" id="IpDnsdiv_txt_@i1"> 60 div> 61 div> 62 <input type="hidden" value="@ip.IpGuid" maxlength="32" name="IpGuid_@i1" id="IpGuid_@i1" /> 63 <input type="hidden" value="@ip.IpName" maxlength="32" name="IpName_@i1" id="IpName_@i1" /> 64 <button onclick="SaveIpConfig(this);" type="button" class="layui-btn" id="btn_@i" lay-filter="btn_@i filter">提交修改button> 65 div> 66 } 67 } 68 div> 69 } 70 } 71 div> 72 div> 73 div> 74 div> 75 div> 76 div> 77 <script type="text/javascript"> 78 var element = layui.element; 79 layui.use('layer'); 80 81 function SaveIpConfig(e) { 82 var btnId = $(e).attr('id'); 83 84 if (btnId == '' || btnId == undefined) return; 85 86 var id = btnId.split('_'); 87 88 if (id.length != 2) return; 89 90 var ip = $("#Ipv4div_txt_" + id[1]).val(); 91 var mask = $("#IpMaskdiv_txt_" + id[1]).val(); 92 var getWay = $("#IpGetWay_txt_" + id[1]).val(); 93 var dns = $("#IpDnsdiv_txt_" + id[1]).val(); 94 var nid = $("#IpGuid_" + id[1]).val(); 95 var ipName = $("#IpName_" + id[1]).val(); 96 97 if ($.trim(ip) == '') { 98 layer.alert('请填写IP地址', 99 { 100 title: '错误' 101 }); 102 return; 103 } else { 104 if (!validateIP($.trim(ip))) { 105 layer.alert('IP地址格式不正确', 106 { 107 title: '错误' 108 }); 109 return; 110 } 111 } 112 113 if (mask.trim() == '') { 114 layer.alert('请填写子网掩码', { 115 title: '错误' 116 }); 117 return; 118 } else { 119 if (!validateIP($.trim(mask))) { 120 layer.alert('子网掩码格式不正确', 121 { 122 title: '错误' 123 }); 124 return; 125 } 126 } 127 128 if ($.trim(getWay) != '' && !validateIP($.trim(getWay))) { 129 layer.alert('网关地址格式不正确', { 130 title: '错误' 131 }); 132 return; 133 } 134 135 if ($.trim(dns) != '' && !validateIP($.trim(dns))) { 136 layer.alert('DNS格式不正确', { 137 title: '错误' 138 }); 139 return; 140 } 141 142 layer.confirm('确定要修改服务器IP吗?!', 143 { icon: 3, title: '信息' }, 144 function(index) { 145 layer.close(index); 146 index = layer.load(0); 147 $.ajax({ 148 type: 'POST', 149 url: '/ChangeIp/SaveIpConfig', 150 data: { ip: ip, mask: mask, getWay: getWay, dns: dns, nid: nid, ipName: ipName}, 151 dataType: "json", 152 success: function(result) { 153 if (result != '' && result != 'undefined') { 154 if (result.code != "200") { 155 layer.alert(result.msg, 156 { 157 title: '错误' 158 }); 159 return; 160 } else { 161 layer.alert('修改成功,请3秒后访问新的IP地址来使用系统。', 162 { 163 title: '成功' 164 }); 165 } 166 } 167 else { 168 layer.alert('返回数据错误。', { 169 title: '错误' 170 }); 171 } 172 }, 173 complete: function(xhr, ts) { 174 layer.close(index); 175 } 176 }); 177 return false; 178 }); 179 } 180 function validateIP(str) { 181 var 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 return re.test(str); 183 } 184 script>

后台VM实体

 1 namespace ViewModel
 2 {
 3     public class IPVm
 4     { 
 3         /// 
 4         /// 本地IP地址
 5         /// 
 6         public List IpList { get; set; }
 7     }
 8 }

IpModel实体

namespace Model
{
    /// 
    /// 获取本地IP地址信息
    /// 
    public class IpModel
    {
        /// 
        /// IP配置文件路径
        /// 
        public string IpConfigFile { get; set; }
        /// 
        /// 名称
        /// 
        public string IpName { get; set; }
        /// 
        /// 一个随机编号
        /// 
        public string IpGuid { get; set; }
        /// 
        /// IPv4的地址
        /// 
        public string Ipv4 { get; set; }
        /// 
        /// IPv6的地址
        /// 
        public string Ipv6 { get; set; }
        /// 
        /// 子网掩码
        /// 
        public string IpMask { get; set; }
        /// 
        /// 网关地址
        /// 
        public string IpGetWay { get; set; }
        /// 
        /// DNS地址
        /// 
        public string IpDns { get; set; }
    }
}

后台Controller实现修改IP地址

  1 using Microsoft.AspNetCore.Mvc;
  2 using Microsoft.Extensions.Logging;
  3 using MidSoft.Sfrz.Model;
  4 using System;
  5 using System.Collections.Generic;
  6 using System.Diagnostics;
  7 using System.IO;
  8 using System.Linq;
  9 using System.Net;
 10 using System.Net.NetworkInformation;
 11 using System.Threading.Tasks;
 12 
 13 namespace Controllers
 14 {
 15     public class ChangeIpController : Controller
 16     {
 17         private readonly ILogger _logger;
 18         public ChangeIpController( ILogger logger)
 19         {
 20             _logger = logger;
 21         }
 22 
 23         public IActionResult Index()
 24         {
 25             #region 获取IP地址
 26 
 27             var IpList = new List();
 28             try
 29             {
 30                 var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
 31                 foreach (var nic in networkInterfaces)
 32                 {
 33                     if (string.Equals("loopback", nic.Name) || string.Equals("lo", nic.Name)) continue;
 34 
 35                     var ipModel = new IpModel();
 36 
 37                     var file = Path.Combine("/", "etc", "sysconfig", "network-scripts", $"ifcfg-{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 = new 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[1]);
 66                                 }
 67                             }
 68                         }
 69 #if DEBUG
 70                         _logger.LogInformation($"DicLength:{ipDictionary.Count}");
 71                         _logger.LogInformation("==========IPEnd============");
 72 #endif
 73                         if (ipDictionary.Any())
 74                         {
 75                             if (ipDictionary.ContainsKey("NAME")) ipModel.IpName = ipDictionary["NAME"].Replace("\"", "");
 76                             if (ipDictionary.ContainsKey("UUID")) ipModel.IpGuid = ipDictionary["UUID"].Replace("\"", "");
 77                             if (ipDictionary.ContainsKey("IPADDR")) ipModel.Ipv4 = ipDictionary["IPADDR"].Replace("\"", "");
 78                             if (ipDictionary.ContainsKey("PREFIX"))
 79                             {
 80                                 int.TryParse(ipDictionary["PREFIX"].Replace("\"", ""), 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                             if (ipDictionary.ContainsKey("GATEWAY")) ipModel.IpGetWay = ipDictionary["GATEWAY"].Replace("\"", "");
 94                             if (ipDictionary.ContainsKey("DNS1")) ipModel.IpDns = ipDictionary["DNS1"].Replace("\"", "");
 95                             if (ipDictionary.ContainsKey("DNS2")) ipModel.IpDns = ipDictionary["DNS2"].Replace("\"", "");
 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         /// 
119         [HttpPost]
120  
121         public async Task SaveIpConfig()
122         {
123             var ip = Request.Form["ip"];
124             var mask = Request.Form["mask"];
125             var getWay = Request.Form["getWay"];
126             var dns = Request.Form["dns"];
127             var nid = Request.Form["nid"];
128             var ipName = Request.Form["ipName"];
129 
130             if (string.IsNullOrWhiteSpace(ip))
131             {
132                 return new JsonResult(new { code = "300", msg = "请填写IP地址" });
133             }
134             if (!IPAddress.TryParse(ip, out _))
135             {
136                 return new JsonResult(new { code = "300", msg = "IP地址格式不正确" });
137             }
138             if (!IPAddress.TryParse(mask, out _))
139             {
140                 return new JsonResult(new { code = "300", msg = "子网掩码地址格式不正确" });
141             }
142 
143             if (string.IsNullOrEmpty(mask) || mask.ToString().Split('.').Length != 4)
144             {
145                 return null;
146             }
147 
148             var ips = mask.ToString().Split('.');
149             
150             var ipMask = 0;
151             var ip1 = Ip2Mask(ips[0]);
152             var ip2 = Ip2Mask(ips[1]);
153             var ip3 = Ip2Mask(ips[2]);
154             var ip4 = Ip2Mask(ips[3]);
155             if (ip1 == null|| ip2 == null|| ip3 == null|| ip4 == null)
156             {
157                 return new JsonResult(new { code = "300", msg = "子网掩码填写不正确" });
158             }
159 
160             ipMask = (int)ip1 + (int)ip2 + (int)ip3 + (int)ip4;
161 
162             if (ipMask == 0)
163             {
164                 return new JsonResult(new { code = "300", msg = "子网掩码填写不正确" });
165             }
166 
167             if (!string.IsNullOrWhiteSpace(getWay) && !IPAddress.TryParse(ip, out _))
168             {
169                 return new JsonResult(new { code = "300", msg = "网关地址格式不正确" });
170             }
171 
172             if (!string.IsNullOrWhiteSpace(dns) && !IPAddress.TryParse(dns, out _))
173             {
174                 return new JsonResult(new { code = "300", msg = "DNS格式不正确" });
175             }
176 
177             if (string.IsNullOrWhiteSpace(ipName))
178             {
179                 ipName = "enp1s0";
180             }
181             if (string.IsNullOrWhiteSpace(nid))
182             {
183                 nid = Guid.NewGuid().ToString("D");
184             }
185 
186             Task.Run(async () =>
187             {
188 
189                 var file = Path.Combine("/", "etc", "sysconfig", "network-scripts", $"ifcfg-{ipName}");
190                 await Task.Delay(200);
191                 try
192                 {
193                     using (var fileStream = new FileStream(file, FileMode.Create))
194                     {
195                         using (var fileStreamWriter = new StreamWriter(fileStream))
196                         {
197                             await fileStreamWriter.WriteLineAsync(@"TYPE=""Ethernet""");
198                             await fileStreamWriter.WriteLineAsync(@"PROXY_METHOD=""none""");
199                             await fileStreamWriter.WriteLineAsync(@"BROWSER_ONLY=""no""");
200                             await fileStreamWriter.WriteLineAsync(@"BOOTPROTO=""none""");
201                             await fileStreamWriter.WriteLineAsync(@"DEFROUTE=""yes""");
202                             await fileStreamWriter.WriteLineAsync(@"IPV4_FAILURE_FATAL=""no""");
203                             await fileStreamWriter.WriteLineAsync(@"IPV6INIT=""yes""");
204                             await fileStreamWriter.WriteLineAsync(@"IPV6_AUTOCONF=""yes""");
205                             await fileStreamWriter.WriteLineAsync(@"IPV6_DEFROUTE=""yes""");
206                             await fileStreamWriter.WriteLineAsync(@"IPV6_FAILURE_FATAL=""no""");
207                             await fileStreamWriter.WriteLineAsync(@"IPV6_ADDR_GEN_MODE=""stable-privacy""");
208                             await fileStreamWriter.WriteLineAsync($@"NAME=""{ipName}""");
209                             await fileStreamWriter.WriteLineAsync($@"UUID=""{nid}""");
210                             await fileStreamWriter.WriteLineAsync($@"DEVICE=""{ipName}""");
211                             await fileStreamWriter.WriteLineAsync(@"ONBOOT=""yes""");
212                             await fileStreamWriter.WriteLineAsync($@"IPADDR=""{ip}""");
213                             await fileStreamWriter.WriteLineAsync($@"PREFIX=""{ipMask}""");
214                             await fileStreamWriter.WriteLineAsync($@"GATEWAY=""{getWay}""");
215                             await fileStreamWriter.WriteLineAsync($@"DNS1=""{dns}""");
216                             await fileStreamWriter.WriteLineAsync(@"IPV6_PRIVACY=""no""");
217                         }
218                     }
219 
220                     await Process.Start("service", " network restart")?.WaitForExitAsync()!;
221                 }
222                 catch (Exception e)
223                 {
224                     _logger.LogError($"修改服务器IP地址出错:{e}");
225                 }
226 
227             });
228             return new JsonResult(new { code = "200" });
229         }
230 
231         #endregion
232 
233         #region 子网掩码位数转子网掩码IP
234 
235         private Tuple<int, int, int, int> Int2IpMask(int ipLength)
236         {
237             int ip1 = 0, ip2 = 0, ip3 = 0, ip4 = 0;
238             var tmpvar = ipLength;
239             if (tmpvar > 32 || tmpvar < 0)
240             {
241                 return null;
242             }
243 
244             if (tmpvar >= 8)
245             {
246                 ip1 = 255;
247                 tmpvar -= 8;
248             }
249             else
250             {
251                 ip1 = Int2BitMask(tmpvar);
252                 return new Tuple<int, int, int, int>(ip1, 0, 0, 0);
253             }
254             if (tmpvar >= 8)
255             {
256                 ip2 = 255;
257                 tmpvar -= 8;
258             }
259             else
260             {
261                 ip2 = Int2BitMask(tmpvar);
262                 return new Tuple<int, int, int, int>(ip1, ip2, 0, 0);
263             }
264             if (tmpvar >= 8)
265             {
266                 ip3 = 255;
267                 tmpvar -= 8;
268             }
269             else
270             {
271                 ip3 = Int2BitMask(tmpvar);
272                 return new Tuple<int, int, int, int>(ip1, ip2, ip3, 0);
273             }
274             ip4 = Int2BitMask(tmpvar);
275             return new Tuple<int, int, int, int>(ip1, ip2, ip3, ip4);
276         }
277 
278         private int Int2BitMask(int num)
279         {
280             if (num >= 8)
281             {
282                 return (255);
283             }
284             var pianyiliang = 0xff00;
285             while (num > 0)
286             {
287                 pianyiliang = pianyiliang >> 1;
288                 num--;
289             }
290             return (pianyiliang & 0xff);
291         }
292         #endregion
293 
294         #region 子网掩码IP地址转位数
295         private int? Ip2Mask(string ip)
296         {
297             int.TryParse(ip, out var num);
298             if (num == 255)
299             {
300                 return 8;
301             }
302             var pianyiliang = 0xff00;
303             var i = 0;
304             while (i < 8)
305             {
306                 if (num == (pianyiliang & 0xff))
307                 {
308                     return i;
309                 }
310                 pianyiliang >>= 1;
311                 i++;
312             }
313             return null;
314         }
315         #endregion
316     }
317 }