海运的博客

sftpgo使用及占用内存较大解决

发布时间:December 9, 2020 // 分类: // No Comments

编译windows下版本,数据库使用bolt,禁用sql。

git clone https://github.com/drakkan/sftpgo.git
cd sftpgo
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -tags nogcs,nos3,noazblob,nomysql,nosqlite,nopgsql,noportable,novaultkms,noawskms,nogcpkms -ldflags "-s -w"
go build -tags nogcs,nos3,noazblob,nomysql,nobolt,nopgsql,noportable,novaultkms,noawskms,nogcpkms -trimpath -ldflags "-s -w -X github.com/drakkan/sftpgo/v2/version.commit=`git describe --always --dirty` -X github.com/drakkan/sftpgo/v2/version.date=`date -Is`" -o sftpgo

使用vbs脚本启动隐藏cmd窗口并重定向日志到nul:

set ws=createobject("wscript.shell")
ws.CurrentDirectory="d:\Program Files\sftpgo\"
ws.run """d:\Program Files\sftpgo\sftpgo.exe"" serve -v=0 -l """" 2> nul",0
wscript.quit

sftpgo默认认证用户密码使用argon2id,当连接数较多时会占用大量内存,通过web新建用户时密码可直接输入sha512crypt密码密文,后续认证时则使用sha512crypt认证,大幅减小内存占用,密码生成:

echo 123456|openssl passwd -6 -in -

sftpgo默认为根目录和子目录添加.和..,添加后会有一些莫名其妙的问题,不添加客户端也可处理与上级目录的关系:

--- ftpd/handler.go     2022-03-11 15:24:52.147555506 +0800
+++ ftpd/handler.go.bak 2022-03-11 15:17:43.300412122 +0800
@@ -14,7 +14,7 @@
        "github.com/drakkan/sftpgo/v2/common"
        "github.com/drakkan/sftpgo/v2/dataprovider"
        "github.com/drakkan/sftpgo/v2/logger"
-       //"github.com/drakkan/sftpgo/v2/util"
+       "github.com/drakkan/sftpgo/v2/util"
        "github.com/drakkan/sftpgo/v2/vfs"
 )
 
@@ -288,10 +288,10 @@
        if err != nil {
                return files, err
        }
-       //if name != "/" {
-       //      files = util.PrependFileInfo(files, vfs.NewFileInfo("..", true, 0, time.Now(), false))
-       //}
-       //files = util.PrependFileInfo(files, vfs.NewFileInfo(".", true, 0, time.Now(), false))
+       if name != "/" {
+               files = util.PrependFileInfo(files, vfs.NewFileInfo("..", true, 0, time.Now(), false))
+       }
+       files = util.PrependFileInfo(files, vfs.NewFileInfo(".", true, 0, time.Now(), false))
        return files, nil
 }

注意:当sftpgo以普通用户运行时db所在目录sftpgo运行用户要有写入权限,否则就算db文件可写sftpgo也提示db只读。
参考:
https://github.com/drakkan/sftpgo/blob/master/docs/account.md

使用ipset导入国家ip数据库替换geoip

发布时间:December 3, 2020 // 分类: // No Comments

使用firehol生成的各个国家ip段数据库,包含geolite2、ipip.net、ip2location,geolite2貌似不再更新。

wget https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/ipip_country/ipip_country_cn.netset
echo 'create cn hash:net -exist' > ipset_cn.rule
while read line; do  if [[ $line =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} ]];then echo "add cn $line";fi;done < ipip_country_cn.netset >> ipset_cn.rule
ipset restore --file ipset_cn.rule

iptables使用:

iptables -A INPUT -m state --state NEW -p tcp --dport 80 -m set --match-set cn src -j ACCEPT

自己生成ipip各个国家ip数据库:

wget https://cdn.ipip.net/17mon/country.zip
unzip country.zip country.txt
mkdir ip
for cy in `awk '{print $2}' country.txt|sort -u`;do awk '{if ($2 == "'$cy'") print $1}' country.txt > ip/$cy.txt;done

生成geoliste2的中国ip数据:

echo 'create cn6 hash:net family inet6 -exist' > ipset_cn6.rule
awk -F',' '{if ($2 == 1814991) print ("add cn6",$1)}' GeoLite2-Country-Blocks-IPv6.csv >> ipset_cn6.rule
echo 'create cn hash:net -exist' > ipset_cn4.rule
awk -F',' '{if ($2 == 1814991) print ("add cn4",$1)}' GeoLite2-Country-Blocks-IPv4.csv >> ipset_cn4.rule

这个网址可在线生成:https://www.ip2location.com/free/visitor-blocker
也可使用此工具自己生成MaxMind geolite2和dbip国家ip数据:
https://github.com/chr0mag/geoipsets

小内存vps使用luks/cryptsetup全盘加密遇到的问题

发布时间:December 2, 2020 // 分类: LUKS // No Comments

有一512M内存vps,在使用pressed安装ubuntu luks加密时一直卡在分区那里,查看日志由于占用内存较高cryptsetup被kill,然后在本机制作一个ubuntu系统img模板dd到目标vps,启动后输入加密密码时提示密码错误,查看日志同样cryptsetup被kill,查找资料原来luks默认为版本2,PBKDF为argon2i,而argon2i比较占用内存。
解决方法:在preseed分区之前修改分区脚本添加参数使用pbkdf2或luks1:

d-i partman/early_command string sed -i 's/luksFormat/--pbkdf pbkdf2 luksFormat/' /lib/partman/lib/crypto-base.sh;
#d-i partman/early_command string sed -i 's/luksFormat/--type luks1 luksFormat/' /lib/partman/lib/crypto-base.sh;

也可指定argon2i最大使用内存,单位KB:

--pbkdf-memory 25600

对已存在的加密分区可转换:

cryptsetup -v luksDump /dev/sda5
cryptsetup -v --pbkdf pbkdf2 luksConvertKey /dev/sda5
cryptsetup -v convert /dev/sda5 --type luks1

20210208更新:
当前ubuntu20.04.2已添加以下参数可直接选择使用pbkdf2或luks1:

d-i partman-crypto/luksformat_options string --type luks1
d-i partman-crypto/luksformat_options string --pbkdf-memory 65535
d-i partman-crypto/luksformat_options string --pbkdf pbkdf2

也可在安装前自动判断内存小于小于多少设置使用pbkdf2:

d-i partman/early_command string if [ `free|grep Mem|tr -s ' ' ' '|cut -d ' ' -f 2` -lt 819200 ];\
    then debconf-set partman-crypto/luksformat_options "--pbkdf pbkdf2";fi

其实小内存主要是安装时luks默认占用内存过高导致安装失败,而dd的系统原虚拟机内存高,luks在设置密码时根据系统内存自动设置--pbkdf-memory,导致pbkdf-memory参数比vps内存都相差不大,所以dd的系统也不能正常启动,vps在安装前通过--pbkdf-memory设置小内存,后续再添加密码使用自动设置的内存参数就可以了。
参考:
https://lists.debian.org/debian-boot/2020/10/msg00000.html
https://gitlab.com/cryptsetup/cryptsetup/-/issues/372

dnsmasq dhcp ipxe网络安装系统

发布时间:December 2, 2020 // 分类: // 1 Comment

dnsmasq配置dhcp和tftp:

#dhcp-vendorclass=bios,PXEClient:Arch:00000
dhcp-match=set:bios,option:client-arch,0
dhcp-match=set:ipxe,175
dhcp-boot=tag:!ipxe,tag:bios,undionly.kpxe
dhcp-boot=tag:!ipxe,tag:!bios,ipxe.efi
dhcp-boot=tag:ipxe,boot.ipxe
#dhcp-boot=tag:ipxe,http://boot.netboot.xyz
enable-tftp
tftp-root=/srv/tftp/

下载pxe启动要加载的ipxe启动文件,也可自己编译ipxe开启相应的功能。

cd /srv/tftp/
wget https://boot.ipxe.org/undionly.kpxe
wget https://boot.ipxe.org/ipxe.efi

ipxe启动脚本boot.ipxe,更多见使用preseed和kickstart自动安装ubuntu和centos系统

#!ipxe
:start
menu PXE Boot Options
item shell iPXE shell
item ubuntu Ubuntu installation
item exit  Exit to BIOS
choose --default ubuntu --timeout 10000 option && goto ${option}
:shell
shell
:ubuntu
#chain --autofree http://boot.netboot.xyz
set mirror http://mirrors.aliyun.com/
set release focal
set arch amd64
set base-url ${mirror}/ubuntu/dists/${release}/main/installer-${arch}/current/legacy-images/netboot/ubuntu-installer/${arch}
kernel ${base-url}/linux auto=true url=https://www.haiyun.me/ubuntu.cfg keymap=us domain= hostname=ubuntu-server interface=auto netcfg/do_not_use_netplan=true
initrd ${base-url}/initrd.gz
boot
:exit
exit

使用其它机器上tftp服务器,地址:192.168.1.6

#dhcp-vendorclass=bios,PXEClient:Arch:00000
dhcp-match=set:bios,option:client-arch,0
dhcp-match=set:ipxe,175
dhcp-boot=tag:!ipxe,tag:bios,undionly.kpxe,,192.168.1.6
dhcp-boot=tag:!ipxe,tag:!bios,ipxe.efi,,192.168.1.6
dhcp-boot=tag:ipxe,boot.ipxe,,192.168.1.6

ubuntu安装tftp服务器:

apt install tftpd-hpa

参考:
https://wiki.archlinux.org/index.php/dnsmasq#PXE_server
https://dev.to/arachan/ipxe-chainloading-to-use-dnsmasq-and-proxydhcp-4he
https://yangfeiffei.github.io/public/2019/08/12/net-install-centos7-with-ipxe.html

windows下定时截屏对比相似度并关机/待机

发布时间:November 20, 2020 // 分类: // No Comments

先判断上次键盘鼠标活动时间,如果时间较长则隔一段时间截屏判断是否在看视频,如果图片符合相似度则执行待机操作。

#include <windows.h>
#include "bitmap.h"
#include "stdio.h"
#include <time.h>
#include <stdlib.h>
#include <PowrProf.h>
#include <math.h>

void echo(CHAR *str);
int getlastinput();
int CheckFullscreen();
int CaptureImage(CHAR *lpbitmap, int width, int height);
int save(char *outfile, CHAR *lpbitmap, DWORD dwBmpSize, int width, int height);

void echo(CHAR *str) {
  //MessageBox(NULL, str, NULL, MB_OK);
  time_t t1;
  struct tm *newtime;
  char time_str[128];
  t1 = time(NULL);
  newtime=localtime(&t1);
  strftime(time_str, 128, "%Y%m%d_%H%M%S", newtime);
  printf("%s:  %s \n", time_str, str);
  //printf("%s \n", str);
}

int main(int argc, char *argv[]) {
  INT width  = GetSystemMetrics(SM_CXSCREEN);  // 屏幕宽
  INT height = GetSystemMetrics(SM_CYSCREEN);  // 屏幕高
  DWORD dwBmpSize = width *  height * 4;
  INT  WidthBytes = width * 4;
  if (argc == 1) {
    printf("use sleep_time(sec) idle_time(min) similarity(<100) save_bmp(1) debug(1)\n");
    exit(1);
  }
  int sleep_idle, sleep_time, idle_time, save_bmp, debug;
  sleep_idle = sleep_time = idle_time = save_bmp = debug = 0;
  float similarity = 0;
  if (argc > 1)
    sleep_time = atoi(argv[1]);
  if (argc > 2)
    idle_time = atoi(argv[2]);
  if (argc > 3)
    similarity = atof(argv[3]);
  if (argc > 4)
    save_bmp = atoi(argv[4]);
  if (argc > 5)
    debug = atoi(argv[5]);
  if (!sleep_time && !idle_time) {
    exit(1);
  }
  if (sleep_time >= 30) {
    sleep_idle = round(sleep_time/5);
    printf("sleep_idle  = %d\n",  sleep_idle);
    sleep_idle = sleep_idle * 1000;
  } else {
    sleep_idle = sleep_time * 1000;
  }
  sleep_time = sleep_time * 1000; //sec
  idle_time = idle_time * 60 * 1000; //min

  HANDLE hDIB;
  hDIB = GlobalAlloc(GHND, dwBmpSize);
  CHAR *lpbitmap = (char *)GlobalLock(hDIB);
  HANDLE hDIB2;
  hDIB2 = GlobalAlloc(GHND, dwBmpSize);
  CHAR *lpbitmap2 = (char *)GlobalLock(hDIB2);

  if (!CaptureImage(lpbitmap, width, height)) {
    exit(1);
  }

  while (1) {
    //CheckFullscreen();
    long int idle = getlastinput();
    printf("%d \n", idle);
    if (!debug && idle < idle_time) {
      echo ("idle");
      Sleep(sleep_idle);
      continue;
    }
    if (!CaptureImage(lpbitmap2, width,height)) {
      Sleep(5*1000);
      continue;
    }

    int count = 0;
    int cmp = 0;
    int index = 0;
    for (int i = 0;i < width;++i)
    {
      for (int j = 0;j < height;++j)
      {
        count++;
        index = i * 4 + j * WidthBytes;
        if (lpbitmap[index + 2] != lpbitmap2[index + 2] || lpbitmap[index + 1] != lpbitmap2[index + 1] || lpbitmap[index + 0] != lpbitmap2[index + 0]) {
          cmp++;
        }
        //BYTE r = lpbitmap[index + 2];
        //BYTE g = lpbitmap[index + 1];
        //BYTE b = lpbitmap[index + 0];
        //printf("r  = %d\n",  r );
        //printf("g  = %d\n",  g );
        //printf("b  = %d\n",  b );
        //printf("index = %d\n",  index);
        //Sleep(1000);
      }
    }

    printf("count = %d\n", count);
    printf("cmp = %d\n", cmp);
    float percentage = (float)cmp / count * 100.0;
    printf("Percentage = %.2f%%\n", percentage);
    if (!debug && percentage <= similarity) {
      echo("SetSuspendState");
      SetSuspendState(0, 1, 1);
      Sleep(60*1000);
    }

    if (save_bmp == 1 && percentage <= similarity) {
      time_t t1;
      struct tm *newtime;
      char time_str[128];
      char outfile[128];
      t1 = time(NULL);
      newtime=localtime(&t1);
      //strftime(outfile, 128, "%Y%m%d_%H%M%S.bmp", newtime);
      strftime(time_str, 128, "%Y%m%d_%H%M%S", newtime);
      sprintf(outfile,"%s_1_%.2f%%.bmp",time_str,percentage);
      save(outfile,lpbitmap, dwBmpSize, width, height);
      sprintf(outfile,"%s_2_%.2f%%.bmp",time_str,percentage);
      save(outfile,lpbitmap2, dwBmpSize, width,height);
    }

    memcpy(lpbitmap, lpbitmap2, dwBmpSize);
    Sleep(sleep_time);
  }
  // 解锁堆内存并释放
  GlobalUnlock(hDIB);
  GlobalFree(hDIB);
  GlobalUnlock(hDIB2);
  GlobalFree(hDIB2);
  return 0;
}


int CaptureImage(CHAR *lpbitmap, int width, int height)
{
  int ret = 1;
  //GetDesktopWindow()
  HDC hScreenDC = GetDC(NULL); //获取显示设备上下文环境
  HDC hMemoryDC = CreateCompatibleDC(hScreenDC); // 创建与显示设备兼容的内存下文环境(设备描述表)
  if (!hMemoryDC) {
    echo(TEXT("CreateCompatibleDC has failed"));
    ret = 0;
    goto done;
  }

  //创建一个与显示设备描述表兼容的位图
  HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, width, height);
  if (!hBitmap) {
    echo(TEXT("CreateCompatibleBitmap Failed"));
    ret = 0;
    goto done;
  }

  //把位图选到内存设备描述表中
  SelectObject(hMemoryDC, hBitmap);
  //HBITMAP hOldBitmap = (HBITMAP) SelectObject(hMemoryDC, hBitmap);
  //把屏幕设备描述表拷贝到内存设备描述表中。
  if (!BitBlt(
        hMemoryDC,    // 目的DC
        0, 0,        // 目的DC的 x,y 坐标
        width, height, // 目的 DC 的宽高
        hScreenDC,   // 来源DC
        0, 0,        // 来源DC的 x,y 坐标
        SRCCOPY))    // 粘贴方式
  {
    echo(TEXT("BitBlt has failed"));
    ret = 0;
    goto done;
  }

  //BITMAP bmpScreen;
  //Get the BITMAP from the HBITMAP
  //GetObject(hbmScreen, sizeof(BITMAP), &bmpScreen);
  //hBitmap = (HBITMAP) SelectObject(hMemoryDC, hOldBitmap);

  BITMAPINFOHEADER bi;
  bi.biSize = sizeof(BITMAPINFOHEADER);
  bi.biWidth = width;
  bi.biHeight = height;
  bi.biPlanes = 1;
  bi.biBitCount = 32;
  bi.biCompression = BI_RGB;
  bi.biSizeImage = 0;
  bi.biXPelsPerMeter = 0;
  bi.biYPelsPerMeter = 0;
  bi.biClrUsed = 0;
  bi.biClrImportant = 0;

  // 获取兼容位图的位并且拷贝结果到一个 lpbitmap 中.
  GetDIBits(
      hScreenDC,  // 设备环境句柄
      hBitmap,  // 位图句柄
      0,          // 指定检索的第一个扫描线
      (UINT)height, // 指定检索的扫描线数
      lpbitmap,   // 指向用来检索位图数据的缓冲区的指针
      (BITMAPINFO *)&bi, // 该结构体保存位图的数据格式
      DIB_RGB_COLORS // 颜色表由红、绿、蓝(RGB)三个直接值构成
      );

  //printf("sizeof((LPSTR)lpbitmap) = %d\n", sizeof((LPSTR)lpbitmap));
  //printf("sizeof(lpbitmap[0]) = %d\n", sizeof(lpbitmap[0]));

done:
  DeleteObject(hBitmap);
  DeleteObject(hMemoryDC);
  //DeleteDC(hMemoryDC);
  ReleaseDC(NULL, hScreenDC);
  return ret;
}

int getlastinput()
{
  long int      newTicks;        // time value for new ticks
  long int      inputTicks;      // time value for current time
  long int      elapsedTicks;    // time value for elapsed time
  LASTINPUTINFO lii;             // Structure for Windows time stuff

  // Set size of lii.cbsize
  lii.cbSize = sizeof(lii);

  // Get the time of the most recent (new) user input
  GetLastInputInfo(&lii);
  newTicks = lii.dwTime;

  inputTicks = GetTickCount();
  elapsedTicks = inputTicks - newTicks;

  return elapsedTicks;
}

int CheckFullscreen() {
  int bFullScreen = 0;
  HWND hWnd = GetForegroundWindow();
  RECT rcApp, rcDesk;
  GetWindowRect(GetDesktopWindow(), &rcDesk);

  if (hWnd!=GetDesktopWindow() && hWnd!=GetShellWindow()) {
    GetWindowRect(hWnd, &rcApp);
    if (rcApp.left<=rcDesk.left && rcApp.top<=rcDesk.top && rcApp.right>=rcDesk.right && rcApp.bottom>=rcDesk.bottom) {
      char wnd_name[256];
      char wnd_title[256];
      GetWindowText(hWnd,wnd_title,sizeof(wnd_title));
      GetClassName(hWnd, wnd_name, sizeof(wnd_name));
      printf("title: %s\n", wnd_title);
      printf("name: %s\n", wnd_name);

      if (strcmp(wnd_name, "Windows.UI.Core.CoreWindow") != 0 && strcmp(wnd_name, "WorkerW") != 0){
        bFullScreen =1;
      }
    }
  }
  return bFullScreen;
}

int save(char *outfile, CHAR *lpbitmap, DWORD dwBmpSize, int width, int height) {
  HANDLE hFile;
  DWORD dwSizeofDIB;
  DWORD dwBytesWritten;
  BITMAPFILEHEADER bmfHeader;

  BITMAPINFOHEADER bi;
  bi.biSize = sizeof(BITMAPINFOHEADER);
  bi.biWidth = width;
  bi.biHeight = height;
  bi.biPlanes = 1;
  bi.biBitCount = 32;
  bi.biCompression = BI_RGB;
  bi.biSizeImage = 0;
  bi.biXPelsPerMeter = 0;
  bi.biYPelsPerMeter = 0;
  bi.biClrUsed = 0;
  bi.biClrImportant = 0;

  // 创建一个文件来保存文件截图
  hFile = CreateFile(
      outfile,
      GENERIC_WRITE,
      0,
      NULL,
      CREATE_ALWAYS,
      FILE_ATTRIBUTE_NORMAL,
      NULL
      );

  // 将 图片头(headers)的大小, 加上位图的大小来获得整个文件的大小
  dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

  // 设置 Offset 偏移至位图的位(bitmap bits)实际开始的地方
  bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);

  // 文件大小
  bmfHeader.bfSize = dwSizeofDIB;

  // 位图的 bfType 必须是字符串 "BM"
  bmfHeader.bfType = 0x4D42; //BM

  dwBytesWritten = 0;
  WriteFile(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
  WriteFile(hFile, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);
  WriteFile(hFile, (LPSTR)lpbitmap, dwBmpSize, &dwBytesWritten, NULL);
  // 关闭文件句柄
  CloseHandle(hFile);
  return 0;
}

使用tdm-gcc编译:

gcc screen.c -o screen.exe -lgdi32 -lPowrprof

参考:
https://docs.microsoft.com/zh-cn/windows/win32/gdi/capturing-an-image?redirectedfrom=MSDN
https://lellansin.wordpress.com/2014/03/16/c-gdi-%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE/
https://bbs.csdn.net/topics/390838652?page=4
https://bbs.csdn.net/topics/340205786?page=2
https://blog.csdn.net/haogeai123/article/details/7030583

分类
最新文章
最近回复
  • opnfense: 谢谢博主!!!解决问题了!!!我之前一直以为内置的odhcp6就是唯一管理ipv6的方式
  • liyk: 这个方法获取的IPv6大概20分钟之后就会失效,默认路由先消失,然后Global IPV6再消失
  • 海运: 不好意思,没有。
  • zongboa: 您好,請問一下有immortalwrt設定guest Wi-Fi的GUI教學嗎?感謝您。
  • 海运: 恩山有很多。
  • swsend: 大佬可以分享一下固件吗,谢谢。
  • Jimmy: 方法一 nghtp3步骤需要改成如下才能编译成功: git clone https://git...
  • 海运: 地址格式和udpxy一样,udpxy和msd_lite能用这个就能用。
  • 1: 怎么用 编译后的程序在家里路由器内任意一台设备上运行就可以吗?比如笔记本电脑 m参数是笔记本的...
  • 孤狼: ups_status_set: seems that UPS [BK650M2-CH] is ...
归档