public class ToStringExample4
{
public static void Main1()
{
// Create an array of all supported standard date and time format specifiers.
string[] formats = {"d", "D", "f", "F", "g", "G", "m", "o", "r",
"s", "t", "T", "u", "U", "Y"};
// Create an array of four cultures.
CultureInfo[] cultures = {CultureInfo.GetCultureInfo("de-DE"),
CultureInfo.GetCultureInfo("en-US"),
CultureInfo.GetCultureInfo("es-ES"),
CultureInfo.GetCultureInfo("fr-FR")};
// Define date to be displayed.
DateTime dateToDisplay = new DateTime(2008, 10, 31, 17, 4, 32);
// Iterate each standard format specifier.
foreach (string formatSpecifier in formats)
{
foreach (CultureInfo culture in cultures)
Console.WriteLine("{0} Format Specifier {1, 10} Culture {2, 40}",
formatSpecifier, culture.Name,
dateToDisplay.ToString(formatSpecifier, culture));
Console.WriteLine();
}
}
}
// The example displays the following output:
// d Format Specifier de-DE Culture 31.10.2008
// d Format Specifier en-US Culture 10/31/2008
// d Format Specifier es-ES Culture 31/10/2008
// d Format Specifier fr-FR Culture 31/10/2008
//
// D Format Specifier de-DE Culture Freitag, 31. Oktober 2008
// D Format Specifier en-US Culture Friday, October 31, 2008
// D Format Specifier es-ES Culture viernes, 31 de octubre de 2008
// D Format Specifier fr-FR Culture vendredi 31 octobre 2008
//
// f Format Specifier de-DE Culture Freitag, 31. Oktober 2008 17:04
// f Format Specifier en-US Culture Friday, October 31, 2008 5:04 PM
// f Format Specifier es-ES Culture viernes, 31 de octubre de 2008 17:04
// f Format Specifier fr-FR Culture vendredi 31 octobre 2008 17:04
//
// F Format Specifier de-DE Culture Freitag, 31. Oktober 2008 17:04:32
// F Format Specifier en-US Culture Friday, October 31, 2008 5:04:32 PM
// F Format Specifier es-ES Culture viernes, 31 de octubre de 2008 17:04:32
// F Format Specifier fr-FR Culture vendredi 31 octobre 2008 17:04:32
//
// g Format Specifier de-DE Culture 31.10.2008 17:04
// g Format Specifier en-US Culture 10/31/2008 5:04 PM
// g Format Specifier es-ES Culture 31/10/2008 17:04
// g Format Specifier fr-FR Culture 31/10/2008 17:04
//
// G Format Specifier de-DE Culture 31.10.2008 17:04:32
// G Format Specifier en-US Culture 10/31/2008 5:04:32 PM
// G Format Specifier es-ES Culture 31/10/2008 17:04:32
// G Format Specifier fr-FR Culture 31/10/2008 17:04:32
//
// m Format Specifier de-DE Culture 31. Oktober
// m Format Specifier en-US Culture October 31
// m Format Specifier es-ES Culture 31 de octubre
// m Format Specifier fr-FR Culture 31 octobre
//
// o Format Specifier de-DE Culture 2008-10-31T17:04:32.0000000
// o Format Specifier en-US Culture 2008-10-31T17:04:32.0000000
// o Format Specifier es-ES Culture 2008-10-31T17:04:32.0000000
// o Format Specifier fr-FR Culture 2008-10-31T17:04:32.0000000
//
// r Format Specifier de-DE Culture Fri, 31 Oct 2008 17:04:32 GMT
// r Format Specifier en-US Culture Fri, 31 Oct 2008 17:04:32 GMT
// r Format Specifier es-ES Culture Fri, 31 Oct 2008 17:04:32 GMT
// r Format Specifier fr-FR Culture Fri, 31 Oct 2008 17:04:32 GMT
//
// s Format Specifier de-DE Culture 2008-10-31T17:04:32
// s Format Specifier en-US Culture 2008-10-31T17:04:32
// s Format Specifier es-ES Culture 2008-10-31T17:04:32
// s Format Specifier fr-FR Culture 2008-10-31T17:04:32
//
// t Format Specifier de-DE Culture 17:04
// t Format Specifier en-US Culture 5:04 PM
// t Format Specifier es-ES Culture 17:04
// t Format Specifier fr-FR Culture 17:04
//
// T Format Specifier de-DE Culture 17:04:32
// T Format Specifier en-US Culture 5:04:32 PM
// T Format Specifier es-ES Culture 17:04:32
// T Format Specifier fr-FR Culture 17:04:32
//
// u Format Specifier de-DE Culture 2008-10-31 17:04:32Z
// u Format Specifier en-US Culture 2008-10-31 17:04:32Z
// u Format Specifier es-ES Culture 2008-10-31 17:04:32Z
// u Format Specifier fr-FR Culture 2008-10-31 17:04:32Z
//
// U Format Specifier de-DE Culture Freitag, 31. Oktober 2008 09:04:32
// U Format Specifier en-US Culture Friday, October 31, 2008 9:04:32 AM
// U Format Specifier es-ES Culture viernes, 31 de octubre de 2008 9:04:32
// U Format Specifier fr-FR Culture vendredi 31 octobre 2008 09:04:32
//
// Y Format Specifier de-DE Culture Oktober 2008
// Y Format Specifier en-US Culture October 2008
// Y Format Specifier es-ES Culture octubre de 2008
// Y Format Specifier fr-FR Culture octobre 2008
using System;
using System.Globalization;
public class MainClass
{
public static void Main(string[] args)
{
DateTime dt = DateTime.Now;
String[] format = {
"d", "D",
"f", "F",
"g", "G",
"m",
"r",
"s",
"t", "T",
"u", "U",
"y",
"dddd, MMMM dd yyyy",
"ddd, MMM d \"'\"yy",
"dddd, MMMM dd",
"M/yy",
"dd-MM-yy",
};
string date;
for (int i = 0; i < format.Length; i++)
{
date = dt.ToString(format[i], DateTimeFormatInfo.InvariantInfo);
Console.WriteLine(string.Concat(format[i], " :", date));
}
/** Output.
*
* d :08/17/2000
* D :Thursday, August 17, 2000
* f :Thursday, August 17, 2000 16:32
* F :Thursday, August 17, 2000 16:32:32
* g :08/17/2000 16:32
* G :08/17/2000 16:32:32
* m :August 17
* r :Thu, 17 Aug 2000 23:32:32 GMT
* s :2000-08-17T16:32:32
* t :16:32
* T :16:32:32
* u :2000-08-17 23:32:32Z
* U :Thursday, August 17, 2000 23:32:32
* y :August, 2000
* dddd, MMMM dd yyyy :Thursday, August 17 2000
* ddd, MMM d "'"yy :Thu, Aug 17 '00
* dddd, MMMM dd :Thursday, August 17
* M/yy :8/00
* dd-MM-yy :17-08-00
*/
}
}
<?php /* vim: set expandtab sw=4 ts=4 sts=4: */ /** * phpMyAdmin sample configuration, you can use it as base for * manual configuration. For easier setup you can use setup/ * * All directives are explained in documentation in the doc/ folder * or at <https://docs.phpmyadmin.net/>. * * @package PhpMyAdmin */ declare(strict_types=1);
/** * This is needed for cookie based authentication to encrypt password in * cookie. Needs to be 32 chars long. */ $cfg[‘blowfish_secret’] = ‘gzOatgMa2i5BVE5F2YkM.Tx5fg@YxuBd‘;
/** * Servers configuration */ $i = 0;
/** * First server */ $i++; /* Authentication type */ $cfg[‘Servers’][$i][‘auth_type’] = ‘cookie’; /* Server parameters */ $cfg[‘Servers’][$i][‘host’] = ‘localhost’; $cfg[‘Servers’][$i][‘compress’] = false; $cfg[‘Servers’][$i][‘AllowNoPassword’] = false;
/** * Directories for saving/loading files from server */ $cfg[‘UploadDir’] = ”; $cfg[‘SaveDir’] = ”; $cfg[‘TempDir’] = ‘/tmp’; /** * Whether to display icons or text or both icons and text in table row * action segment. Value can be either of ‘icons’, ‘text’ or ‘both’. * default = ‘both’ */ //$cfg[‘RowActionType’] = ‘icons’;
/** * Defines whether a user should be displayed a “show all (records)” * button in browse mode or not. * default = false */ //$cfg[‘ShowAll’] = true;
/** * Number of rows displayed when browsing a result set. If the result * set contains more rows, “Previous” and “Next”. * Possible values: 25, 50, 100, 250, 500 * default = 25 */ //$cfg[‘MaxRows’] = 50;
/** * Default language to use, if not browser-defined or user-defined * (you find all languages in the locale folder) * uncomment the desired line: * default = ‘en’ */ //$cfg[‘DefaultLang’] = ‘en’; //$cfg[‘DefaultLang’] = ‘de’;
/** * How many columns should be used for table display of a database? * (a value larger than 1 results in some information being hidden) * default = 1 */ //$cfg[‘PropertiesNumColumns’] = 2;
/** * Set to true if you want DB-based query history.If false, this utilizes * JS-routines to display query history (lost by window close) * * This requires configuration storage enabled, see above. * default = false */ //$cfg[‘QueryHistoryDB’] = true;
/** * When using DB-based query history, how many entries should be kept? * default = 25 */ //$cfg[‘QueryHistoryMax’] = 100;
/** * Whether or not to query the user before sending the error report to * the phpMyAdmin team when a JavaScript error occurs * * Available options * (‘ask’ | ‘always’ | ‘never’) * default = ‘ask’ */ //$cfg[‘SendErrorReports’] = ‘always’;
/** * You can find more configuration options in the documentation * in the doc/ folder or at <https://docs.phpmyadmin.net/>. */
실제로 C#에서 아이피를 가져와야할 일이 많다보니 2013년부터 만들어서 앞으로 계속 사용하기 위해서 만든거라 개발하실때 만드시더라도 특별한 일 없는이상 위의 도메인을 유지할겁니다.
2017년도에 기간연장 10년치 최고 결재라서 10년치 결재했는데 벌써 4년 남았네요.
2년정도 남았을때 다시 10년 기간 연장 해놓겠습니다.
직접 C# 프로그램으로 제작해보았습니다.
아래는 제가 C#으로 직접 만든 프로그램 입니다.
c# 외부 ip 가져오기 소스코드
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ESXi_IP_Monitoring
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
label_ip.Text = String.Format("{0}", GetExternalIp());
}
public static IPAddress GetExternalIp()
{
string ip = string.Empty;
try
{
string sourceURL = string.Empty;
sourceURL = string.Format("https://api.tion.kr");
WebClient client = new WebClient();
client.Encoding = Encoding.UTF8;
string data = client.DownloadString(string.Format("https://api.tion.kr"));
string pattern = "(<myip>)(?<ip>[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}?)(</myip>)";
MatchCollection matches = Regex.Matches(data, pattern);
foreach (Match match in matches)
{
if (match.Groups["ip"].Length > 0)
{
//IP 정상적으로 나오는지 확인하는 부분
//MessageBox.Show(match.Groups["ip"].Value);
ip = match.Groups["ip"].Value;
}
}
}
catch (Exception)
{
}
IPAddress externalIp = IPAddress.Parse(ip);
return externalIp;
}
}
}
외부 IP를 잘 가져오는군요.
저는 이렇게 외부 IP를 자동으로 가져와서 ESXi 방화벽에 자동추가하는 시스템을 만들고 있습니다.
외부 어느지역에서도 ESXi 서버에 자유롭게 자동으로 접속하기 위한 시스템이죠.
방화벽으로 특정 IP만 접속 할 수 있도록 만들고 위의 프로그램으로 1분동안 접속 가능하도록 만들고 있습니다.
vmware 사용할때에는 자체 file share 기능을 이용하여 host 폴더를 지정하여 guest vm에서 같은 폴더를 지정하여 사용하였습니다. 그런데 host pc에서 최근들어 강제로 업데이트 되면서 vmware workstation 버전 상관없이 강제 재부팅이 자주 일어나고 있습니다.
이를 해결하기 위해서 xenserver, vmware esxi, 기타 등등 linux 기반에서 vm을 관리하는 방법이 윈도우 10 강제 재부팅을 막을 수 있는 유일한 방법이더군요.
게중에는 윈도우10, 11 업데이트를 막으면 된다는 글들이 많지만 실제로 수도 없이 해보았고 업데이트 안될시 불이익 등등 다 따져보았을때 운영체제를 바꾸는것이 정답이더군요.
결국 ESXi 서버를 도입하게 되었습니다.
그런데 이때 문제가 발생하더군요.
기존에 vmware workstation 에서는 위에서 이미 말씀드린바 공유폴더를 지정할수 있었습니다.
ESXi 와 Xenserver 와 같은 시스템에서는 그러한 부분들이 잘 되어 있지 않아 (제가 모를수도 있고요) 직접 guest vm마다 공유폴더를 만들어서 사용하려합니다.
이렇다보니 윈도우7, 윈도우10 guest vm에서 파일을 강제로 다운받아야 하는데 리눅스처럼 wget 기능이 없어 윈도우 wget 대체 프로그램을 찾다가 파워쉘이 유일한 방법이더군요.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using static System.Net.Mime.MediaTypeNames;
namespace wget
{
internal class Program
{
static void help()
{
Console.WriteLine("wget version: 1.0");
Console.WriteLine("wget: missing URL");
Console.WriteLine("Usage: wget https://vlog.tion.co.kr/app/wget.exe");
Console.WriteLine("");
Console.WriteLine("Try `wget --help` for help");
Console.WriteLine("");
Console.WriteLine("made by 리눅스맨 2023-02-24 vlog.tion.co.kr");
}
static void Main(string[] args)
{
if (args.Length == 0)
{
help();
}
else
{
switch (args.Length)
{
case 1:
if (args[0].Contains("http"))
{
Uri uri = new Uri(args[0]);
string fileName = null;
string[] uriSegments = uri.Segments;
int indexSegment = 0;
foreach (string getFileName in uriSegments)
{
if (++indexSegment == uriSegments.Length)
{
//Console.WriteLine(getFileName);
fileName = WebUtility.UrlDecode(getFileName.Trim());
}
}
string remoteUri = uri.OriginalString;
string myStringWebResource = remoteUri;
// Create a new WebClient instance.
WebClient myWebClient = new WebClient();
// Concatenate the domain with the Web resource filename.
Console.WriteLine("Downloading File \"{0}\" from \"{1}\" .......\n\n", fileName, myStringWebResource);
// Download the Web resource and save it into the current filesystem folder.
myWebClient.DownloadFile(myStringWebResource, fileName);
Console.WriteLine("Successfully Downloaded File \"{0}\" from \"{1}\"", fileName, myStringWebResource);
Console.WriteLine("\nDownloaded file saved");
}
else if (args[0].Equals("--help"))
{
}
else
{
help();
}
break;
}
}
}
}
}
이제 필요한 파일을 웹서버 하나 만들어서 업로드 하고 필요할때마다 wget.exe 파일 이용해서 다운받으면됩니다.
3일정도를 분단위로 로그를 저장하고 있는데 하루에 한번씩 20분정도 서버가 멈추는 것으로 파악되었습니다.
그리고 의문의 한가지가 있는데요.
같은 시각 다른 서버에서도 동일한 흔적이 있었습니다.
같은서버가 아님에도 불구하고 같은 시간 동일하게 서버가 다운되었습니다.
그래서 로그를 확인해보니… 해킹시도로 인한 서비스 다운이 된듯합니다.
최근에 관리자 접속이 계속 잠기고 로그인 할 수 없었는데 해커 2명정도가 계속 서버에 붙어서 로그인 시도를 하고 있었네요. 안타깝습니다.
지금 확인하고 있는 가운데에도 계속 저렇게 해킹시도를 하고 있으니…
이벤트 로그에서 해킹시도가 명백해졌으므로 IP 차단으로 해결할 문제는 아닌듯하고
서버 root 접속 시도하는 모든 아이피를 자동으로 차단하도록 해야될꺼같단 생각이 들었습니다.
아마존 EC2 운영은 보안서버가 EC2 서버 앞단에 있어서 방화벽으로IP를 제어할수 있지만
ESXi, Xenserver 같은 개인서버를 운영할 경우 방화벽 단계가 없다보니 애시당초 로그인 자체를 못하게 막아야합니다.
로그인 아이디 단 1번이라도 틀리면 접속을 못하도록 막아버려야 할꺼같습니다.
ESXi 서버를 운영할 경우에는 아래 항목을 찾아서 변경합니다.
Security.AccountLockFailures
사용자 계정을 잠그기 전 허용되는 최대 로그인 실패 횟수입니다. 0은 계정 잠금을 사용하지 않습니다.
5
Security.AccountUnlockTime
허용되는 최대 로그인 시도 실패 횟수를 초과한 후 사용자의 계정을 잠그는 기간(초)입니다.
900
그래서 관련 웹서버 모니터링 서비스를 찾아보았지만 제 맘에 드는게 없어서 직접 만들었습니다.
우선 파이썬3 버전이 설치가 되어져있어야 합니다.
파이썬3 설치에 관련해서는 아래 링크를 참고해주세요.
파이썬3 버전이 설치되었다면 아래 명령어를 그대로 복사 붙여넣기 하면됩니다.
mkdir /root/_TION
cd /root/_TION
wget https://vlog.tion.co.kr/python/tionServerMonitoring.tar
tar xvf tionServerMonitoring.tar
rm -rf tionServerMonitoring.tar
echo "python3 /root/_TION/tionServerMonitoring/memcheck_httpd_restart.py" > /tionServerMonitoring.sh
chmod 701 /tionServerMonitoring.sh
(crontab -l 2>/dev/null; echo "*/1 * * * * /tionServerMonitoring.sh") | crontab
/tionServerMonitoring.sh
ls -a
위의 명령어를 그대로 서버에 SSH 프로그램을 이용하여 복사붙여넣기를 하면 python/tionServerMonitoring.tar 파일을 다운받고 그 파일을 압축풀어서 python3 명령어로 실행을 하게됩니다.
python3: command not found
파이썬3를 설치했음에도 불구하고 위처럼 나타나면 심볼릭을 잡아주시기 바랍니다.
ln -s /usr/bin/python3.8 /usr/bin/python3
이제 python3 명령어로 잘 실행이 되는군요.
이제 다시 [ /tionServerMonitoring.sh ] 쉘스크립트를 실행해보겠습니다.
위에서 이미 설치를 하였기에 다시 또 설치할 필요는 없습니다.
괜히 crontab 항목에 1분마다 서버체크하는 항목만 더 추가되니 2번이상 설치하신분들은 꼭 crontab -e 항목을 확인하셔서 중복된 체킹을 제거해주세요.
[root@amzn2 _TION]# /tionServerMonitoring.sh Traceback (most recent call last): File “/root/_TION/tionServerMonitoring/memcheck_httpd_restart.py”, line 1, in import psutil ModuleNotFoundError: No module named ‘psutil’
이번에는 psutil 이라는 모듈이 없다고 나올겁니다.
pip 명령어를 이용하여 psutil, stdin모듈을 설치해주세요
pip install psutil stdin
만약 pip 명령어가 없다고 나올 경우
-bash: pip: command not found
pip를 설치해야합니다.
아래 링크에서 pip install 설치를 우선 확인하고 설치해주세요. (이 글 본문에도 링크 아랫쪽에 넣어두긴했습니다)