<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[MMA🥊JAZZ]]></title><description><![CDATA[MMA & MUSIC]]></description><link>https://zzs0.com/</link><image><url>https://zzs0.com/favicon.png</url><title>MMA🥊JAZZ</title><link>https://zzs0.com/</link></image><generator>Ghost 3.36</generator><lastBuildDate>Tue, 10 Jun 2025 07:22:37 GMT</lastBuildDate><atom:link href="https://zzs0.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[PM3编译安装GUI]]></title><description><![CDATA[<h3 id="-pm3">安装pm3</h3><ol><li>brew install xquartz</li><li>brew tap RfidResearchGroup/proxmark3</li><li>brew install --with-generic proxmark3</li></ol><p>如果link失败, 则需要删除rm -rf /usr/local/share/proxmark3</p><p>然后执行 brew link proxmark3</p><h3 id="-">刷机</h3><ol><li>不通电按住按钮</li><li>插入usb接口, 4个灯会亮两个, 然后松手</li><li>如果松手后灯变了, 是老版本固件,需要重复1,2步骤, 然后不松手一直按住</li><li>执行 pm3-flash-all</li></ol><h3 id="-pm3-gui">安装pm3 GUI</h3><ol><li>安装参考<a href="https://github.com/wh201906/Proxmark3GUI/blob/master/doc/README/README_zh_CN.md">https://github.com/wh201906/Proxmark3GUI/blob/master/doc/README/README_zh_CN.</a></li></ol>]]></description><link>https://zzs0.com/pm3bian-yi-an-zhuang-gui/</link><guid isPermaLink="false">660bd79e37eedf000179757e</guid><dc:creator><![CDATA[MMA🐵JAZZ]]></dc:creator><pubDate>Tue, 02 Apr 2024 10:17:41 GMT</pubDate><content:encoded><![CDATA[<h3 id="-pm3">安装pm3</h3><ol><li>brew install xquartz</li><li>brew tap RfidResearchGroup/proxmark3</li><li>brew install --with-generic proxmark3</li></ol><p>如果link失败, 则需要删除rm -rf /usr/local/share/proxmark3</p><p>然后执行 brew link proxmark3</p><h3 id="-">刷机</h3><ol><li>不通电按住按钮</li><li>插入usb接口, 4个灯会亮两个, 然后松手</li><li>如果松手后灯变了, 是老版本固件,需要重复1,2步骤, 然后不松手一直按住</li><li>执行 pm3-flash-all</li></ol><h3 id="-pm3-gui">安装pm3 GUI</h3><ol><li>安装参考<a href="https://github.com/wh201906/Proxmark3GUI/blob/master/doc/README/README_zh_CN.md">https://github.com/wh201906/Proxmark3GUI/blob/master/doc/README/README_zh_CN.md</a></li><li> 启动后设置界面, 设置客户端路径为/usr/local/bin/pm3</li><li>设置启动参数为-p /dev/tty.usbmodemiceman1 -f</li><li>然后刷新端口, 连接</li></ol><h3 id="-pm3-gui-1">使用pm3 GUI</h3><ol><li>先读卡信息选择合适的卡</li><li>执行破解, 先验证默认密码, 解不了的话尝试其他方法破解</li><li>破解出密码后读取选中块, 如果有块失败可以多读取几次</li><li>UID卡读取后可以直接写</li><li>手环的话需要把密钥不是默认的改为默认密钥(12个F),  然后写入UID卡, 再用手环复制</li><li>某些块读取写入失败的话可以单独选中该块, 反复尝试</li></ol>]]></content:encoded></item><item><title><![CDATA[Nexus 6p刷机]]></title><description><![CDATA[<ol><li>安装adb</li><li>下载完整的OTA镜像<a href="https://developers.google.cn/android/images?hl=zh-cn#angler">https://developers.google.cn/android/images?hl=zh-cn#angler</a></li><li>手机进入bootloader：<code>adb reboot bootloader</code>，解压镜像，运行 <code>flash-all.bat</code> 等待安装</li><li>或者关机后手机按开机键和音量下，进入bootloader，音量键选择进入recover，选择sideloader，adb sideload img.zip</li><li>安装完后，手机点击电源键让手机正常启动，手机刷机升级成功！<br>在手机上找到设置→系统→关于手机→版本号，点击版本号五下，打开开发者选项，然后进入设置→系统→开发者选项，打开USB调试选项。然后USB连接到电脑，使用adb命令连上去或拔插数据线，保证USB连接没有问题。然后继续往下看。。。</li><li>在github项目主页的release页面，下载最新的卡刷包：<a href="https://github.com/topjohnwu/Magisk/releases/tag/v20.4">Magisk v20.4</a></li></ol>]]></description><link>https://zzs0.com/nexus-6pshua-ji/</link><guid isPermaLink="false">6421094080503a0001e47f77</guid><dc:creator><![CDATA[MMA🐵JAZZ]]></dc:creator><pubDate>Mon, 27 Mar 2023 03:23:10 GMT</pubDate><content:encoded><![CDATA[<ol><li>安装adb</li><li>下载完整的OTA镜像<a href="https://developers.google.cn/android/images?hl=zh-cn#angler">https://developers.google.cn/android/images?hl=zh-cn#angler</a></li><li>手机进入bootloader：<code>adb reboot bootloader</code>，解压镜像，运行 <code>flash-all.bat</code> 等待安装</li><li>或者关机后手机按开机键和音量下，进入bootloader，音量键选择进入recover，选择sideloader，adb sideload img.zip</li><li>安装完后，手机点击电源键让手机正常启动，手机刷机升级成功！<br>在手机上找到设置→系统→关于手机→版本号，点击版本号五下，打开开发者选项，然后进入设置→系统→开发者选项，打开USB调试选项。然后USB连接到电脑，使用adb命令连上去或拔插数据线，保证USB连接没有问题。然后继续往下看。。。</li><li>在github项目主页的release页面，下载最新的卡刷包：<a href="https://github.com/topjohnwu/Magisk/releases/tag/v20.4">Magisk v20.4</a><br>然后使用adb命令将卡刷包上传到手机中去。</li><li>adb push Magisk-v20.4.zip /sdcard/</li><li>然后adb reboot bootloader使手机进入bootloader，并执行命令fastboot flash recovery twrp-3.4.0-0-angler_en.img刷入twrp，刷完之后，在手机上按两次音量向下键，选择Recovery mode，按电源键进入，进入后直接滑开即可，意味着允许修改系统。<br>再点击Install。然后选择我们刚刚传输进去的Magisk-v20.4.zip卡刷包。滑动确认安装。<br>安装完成后直接重启即可Reboot System。继续滑动Swipe to Install TWRP App。<br>重启后发现Magisk Manager已经安装好了，并且是作为系统App，卸载不了的。卸载只有安装官网release页面里的Magisk-uninstaller.zip卡刷包。<br></li><li>adb shell settings put global wifi_sleep_policy 2 调整wifi休眠策略</li><li>可运行目录在/data/local, 需要chmod 777 可执行文件</li></ol>]]></content:encoded></item><item><title><![CDATA[使用CF workers反代网站]]></title><description><![CDATA[<p>普通反代</p><pre><code class="language-javascript">// 替换成你想镜像的站点
const upstream = "www.google.com";

// 如果那个站点有专门的移动适配站点，否则保持和上面一致
const upstream_mobile = "www.google.com";

// 你希望禁止哪些国家访问
const blocked_region = ["RU"];

// 禁止自访问
const blocked_ip_address = ["0.0.0.0", "127.0.0.1"];

// 替换成你想镜像的站点
const replace_dict = {
  $upstream: "$custom_domain",
  "//www.google.com": ""
};

//以下内容都不用动
addEventListener("fetch", (event) =&gt; {
  event.respondWith(</code></pre>]]></description><link>https://zzs0.com/shi-yong-cf/</link><guid isPermaLink="false">6368bf06e65e900001bc8a75</guid><dc:creator><![CDATA[MMA🐵JAZZ]]></dc:creator><pubDate>Mon, 07 Nov 2022 08:22:08 GMT</pubDate><content:encoded><![CDATA[<p>普通反代</p><pre><code class="language-javascript">// 替换成你想镜像的站点
const upstream = "www.google.com";

// 如果那个站点有专门的移动适配站点，否则保持和上面一致
const upstream_mobile = "www.google.com";

// 你希望禁止哪些国家访问
const blocked_region = ["RU"];

// 禁止自访问
const blocked_ip_address = ["0.0.0.0", "127.0.0.1"];

// 替换成你想镜像的站点
const replace_dict = {
  $upstream: "$custom_domain",
  "//www.google.com": ""
};

//以下内容都不用动
addEventListener("fetch", (event) =&gt; {
  event.respondWith(fetchAndApply(event.request));
});

async function fetchAndApply(request) {
  const region = request.headers.get("cf-ipcountry").toUpperCase();
  const ip_address = request.headers.get("cf-connecting-ip");
  const user_agent = request.headers.get("user-agent");

  let response = null;
  let url = new URL(request.url);
  let url_host = url.host;

  if (url.protocol == "http:") {
    url.protocol = "https:";
    response = Response.redirect(url.href);
    return response;
  }

  if (await device_status(user_agent)) {
    upstream_domain = upstream;
  } else {
    upstream_domain = upstream_mobile;
  }

  url.host = upstream_domain;

  if (blocked_region.includes(region)) {
    response = new Response(
      "Access denied: WorkersProxy is not available in your region yet.",
      {
        status: 403
      }
    );
  } else if (blocked_ip_address.includes(ip_address)) {
    response = new Response(
      "Access denied: Your IP address is blocked by WorkersProxy.",
      {
        status: 403
      }
    );
  } else {
    let method = request.method;
    let request_headers = request.headers;
    let new_request_headers = new Headers(request_headers);

    new_request_headers.set("Host", upstream_domain);
    new_request_headers.set("Referer", url.href);

    let original_response = await fetch(url.href, {
      method: method,
      headers: new_request_headers
    });

    let original_response_clone = original_response.clone();
    let original_text = null;
    let response_headers = original_response.headers;
    let new_response_headers = new Headers(response_headers);
    let status = original_response.status;

    new_response_headers.set("access-control-allow-origin", "*");
    new_response_headers.set("access-control-allow-credentials", true);
    new_response_headers.delete("content-security-policy");
    new_response_headers.delete("content-security-policy-report-only");
    new_response_headers.delete("clear-site-data");

    const content_type = new_response_headers.get("content-type");
    if (content_type.includes("text/html") &amp;&amp; content_type.includes("UTF-8")) {
      original_text = await replace_response_text(
        original_response_clone,
        upstream_domain,
        url_host
      );
    } else {
      original_text = original_response_clone.body;
    }

    response = new Response(original_text, {
      status,
      headers: new_response_headers
    });
  }
  return response;
}

async function replace_response_text(response, upstream_domain, host_name) {
  let text = await response.text();

  var i, j;
  for (i in replace_dict) {
    j = replace_dict[i];
    if (i == "$upstream") {
      i = upstream_domain;
    } else if (i == "$custom_domain") {
      i = host_name;
    }

    if (j == "$upstream") {
      j = upstream_domain;
    } else if (j == "$custom_domain") {
      j = host_name;
    }

    let re = new RegExp(i, "g");
    text = text.replace(re, j);
  }
  return text;
}

async function device_status(user_agent_info) {
  var agents = [
    "Android",
    "iPhone",
    "SymbianOS",
    "Windows Phone",
    "iPad",
    "iPod"
  ];
  var flag = true;
  for (var v = 0; v &lt; agents.length; v++) {
    if (user_agent_info.indexOf(agents[v]) &gt; 0) {
      flag = false;
      break;
    }
  }
  return flag;
}
</code></pre><p>带密码的反代</p><pre><code class="language-javascript">// 替换成你想镜像的站点
const upstream = 'google.com'
 
// 如果那个站点有专门的移动适配站点，否则保持和上面一致
const upstream_mobile = 'm.google.com'
 
// 密码访问
 
const openAuth = false
const username = 'username'
const password = 'password'
 
// 你希望禁止哪些国家访问
const blocked_region = ['RU']
 
// 禁止自访问
const blocked_ip_address = ['0.0.0.0', '127.0.0.1']
 
// 替换成你想镜像的站点
const replace_dict = {
    '$upstream': '$custom_domain',
    '//google.com': ''
}
 
function unauthorized() {
  return new Response('Unauthorized', {
    headers: {
      'WWW-Authenticate': 'Basic realm="goindex"',
      'Access-Control-Allow-Origin': '*'
    },
    status: 401
  });
}
 
function parseBasicAuth(auth) {
    try {
      return atob(auth.split(' ').pop()).split(':');
    } catch (e) {
      return [];
    }
}
 
function doBasicAuth(request) {
  const auth = request.headers.get('Authorization');
 
  if (!auth || !/^Basic [A-Za-z0-9._~+/-]+=*$/i.test(auth)) {
    return false;
  }
 
  const [user, pass] = parseBasicAuth(auth);
  return user === username &amp;&amp; pass === password;
}
 
 
async function fetchAndApply(request) {
  if (request.method === 'OPTIONS') // allow preflight request
    return new Response('', {
      status: 200,
      headers: {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Headers': '*',
        'Access-Control-Allow-Methods': 'GET, POST, PUT, HEAD, OPTIONS'
      }
    });
 
  if (openAuth &amp;&amp; !doBasicAuth(request)) {
    return unauthorized();
  }
    const region = request.headers.get('cf-ipcountry').toUpperCase();
    const ip_address = request.headers.get('cf-connecting-ip');
    const user_agent = request.headers.get('user-agent');
 
    let response = null;
    let url = new URL(request.url);
    let url_host = url.host;
 
    if (url.protocol == 'http:') {
        url.protocol = 'https:'
        response = Response.redirect(url.href);
        return response;
    }
 
    if (await device_status(user_agent)) {
        upstream_domain = upstream
    } else {
        upstream_domain = upstream_mobile
    }
 
    url.host = upstream_domain;
 
    if (blocked_region.includes(region)) {
        response = new Response('Access denied: WorkersProxy is not available in your region yet.', {
            status: 403
        });
    } else if(blocked_ip_address.includes(ip_address)){
        response = new Response('Access denied: Your IP address is blocked by WorkersProxy.', {
            status: 403
        });
    } else{
        let method = request.method;
        let request_headers = request.headers;
        let new_request_headers = new Headers(request_headers);
 
        new_request_headers.set('Host', upstream_domain);
        new_request_headers.set('Referer', url.href);
 
        let original_response = await fetch(url.href, {
            method: method,
            headers: new_request_headers
        })
 
        let original_response_clone = original_response.clone();
        let original_text = null;
        let response_headers = original_response.headers;
        let new_response_headers = new Headers(response_headers);
        let status = original_response.status;
 
        new_response_headers.set('access-control-allow-origin', '*');
        new_response_headers.set('access-control-allow-credentials', true);
        new_response_headers.delete('content-security-policy');
        new_response_headers.delete('content-security-policy-report-only');
        new_response_headers.delete('clear-site-data');
 
        const content_type = new_response_headers.get('content-type');
        if (content_type.includes('text/html') &amp;&amp; content_type.includes('UTF-8')) {
            original_text = await replace_response_text(original_response_clone, upstream_domain, url_host);
        } else {
            original_text = original_response_clone.body
        }
 
        response = new Response(original_text, {
            status,
            headers: new_response_headers
        })
    }
    return response;
}
 
addEventListener('fetch', event =&gt; {
    event.respondWith(fetchAndApply(event.request).catch(err =&gt; {
      console.error(err);
      new Response(JSON.stringify(err.stack), {
        status: 500,
        headers: {
          'Content-Type': 'application/json'
        }
      });
    }));
})
 
 
async function replace_response_text(response, upstream_domain, host_name) {
    let text = await response.text()
 
    var i, j;
    for (i in replace_dict) {
        j = replace_dict[i]
        if (i == '$upstream') {
            i = upstream_domain
        } else if (i == '$custom_domain') {
            i = host_name
        }
 
        if (j == '$upstream') {
            j = upstream_domain
        } else if (j == '$custom_domain') {
            j = host_name
        }
 
        let re = new RegExp(i, 'g')
        text = text.replace(re, j);
    }
    return text;
}
 
async function device_status (user_agent_info) {
    var agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
    var flag = true;
    for (var v = 0; v &lt; agents.length; v++) { if (user_agent_info.indexOf(agents[v]) &gt; 0) {
            flag = false;
            break;
        }
    }
    return flag;
}</code></pre><p>反代某个目录</p><pre><code class="language-javascript">  // 你要镜像的网站.
const upstream = 'www.google.com'
 
// 镜像网站的目录，比如你想镜像某个网站的二级目录则填写二级目录的目录名，镜像 google 用不到，默认即可.
const upstream_path = '/test/'
 
// 镜像站是否有手机访问专用网址，没有则填一样的.
const upstream_mobile = 'www.google.com'
 
// 屏蔽国家和地区.
const blocked_region = ['']
 
// 屏蔽 IP 地址.
const blocked_ip_address = ['0.0.0.0', '127.0.0.1']
 
// 镜像站是否开启 HTTPS.
const https = true
 
// 文本替换.填你要镜像的网站
const replace_dict = {
    '$upstream': '$custom_domain',
    '//www.google.com': ''
}
 
// 以下保持默认，不要动
addEventListener('fetch', event =&gt; {
    event.respondWith(fetchAndApply(event.request));
})
 
async function fetchAndApply(request) {
 
    const region = request.headers.get('cf-ipcountry').toUpperCase();
    const ip_address = request.headers.get('cf-connecting-ip');
    const user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36"
 
    let response = null;
    let url = new URL(request.url);
    let url_hostname = url.hostname;
 
    if (https == true) {
        url.protocol = 'https:';
    } else {
        url.protocol = 'http:';
    }
 
    if (await device_status(user_agent)) {
        var upstream_domain = upstream;
    } else {
        var upstream_domain = upstream_mobile;
    }
 
    url.host = upstream_domain;
    if (url.pathname == '/') {
        url.pathname = upstream_path;
    } else {
        url.pathname = upstream_path + url.pathname;
    }
 
    if (blocked_region.includes(region)) {
        response = new Response('Access denied: WorkersProxy is not available in your region yet.', {
            status: 403
        });
    } else if (blocked_ip_address.includes(ip_address)) {
        response = new Response('Access denied: Your IP address is blocked by WorkersProxy.', {
            status: 403
        });
    } else {
        let method = request.method;
        let request_headers = request.headers;
        let new_request_headers = new Headers(request_headers);
 
        new_request_headers.set('Host', url.hostname);
        new_request_headers.set('Referer', url.hostname);
 
        let original_response = await fetch(url.href, {
            method: method,
            headers: new_request_headers
        })
 
        let original_response_clone = original_response.clone();
        let original_text = null;
        let response_headers = original_response.headers;
        let new_response_headers = new Headers(response_headers);
        let status = original_response.status;
 
        new_response_headers.set('access-control-allow-origin', '*');
        new_response_headers.set('access-control-allow-credentials', true);
        new_response_headers.delete('content-security-policy');
        new_response_headers.delete('content-security-policy-report-only');
        new_response_headers.delete('clear-site-data');
 
        const content_type = new_response_headers.get('content-type');
        if (content_type.includes('text/html') &amp;&amp; content_type.includes('UTF-8')) {
            original_text = await replace_response_text(original_response_clone, upstream_domain, url_hostname);
        } else {
            original_text = original_response_clone.body
        }
 
        response = new Response(original_text, {
            status,
            headers: new_response_headers
        })
    }
    return response;
}
 
async function replace_response_text(response, upstream_domain, host_name) {
    let text = await response.text()
 
    var i, j;
    for (i in replace_dict) {
        j = replace_dict[i]
        if (i == '$upstream') {
            i = upstream_domain
        } else if (i == '$custom_domain') {
            i = host_name
        }
 
        if (j == '$upstream') {
            j = upstream_domain
        } else if (j == '$custom_domain') {
            j = host_name
        }
 
        let re = new RegExp(i, 'g')
        text = text.replace(re, j);
    }
    return text;
}
 
 
async function device_status(user_agent_info) {
    var agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
    var flag = true;
    for (var v = 0; v &lt; agents.length; v++) {
        if (user_agent_info.indexOf(agents[v]) &gt; 0) {
            flag = false;
            break;
        }
    }
    return flag;
}</code></pre>]]></content:encoded></item><item><title><![CDATA[find 查看删除的三种方式]]></title><description><![CDATA[<p>find 查看删除的三种方式，如删除当前目录下的TXT文件：</p><p>方法1：xargs rm -f</p><pre><code>find ./ -type f -name "*txt" |xargs rm -f</code></pre><p><br>方法2：-exec rm -f<br></p><pre><code>find ./ -type f -name "txt" -exec rm -f {} ;</code></pre><p><br>-exec命令是查找到的每个文件调用一次rm命令，因此速度最慢</p><p>方法3：-delete<br></p><pre><code>find ./ -type f -name "*txt" -delete</code></pre><p><br>如果一次删除大量文件，建议采用第三种方式。经测试在删除千万级文件时，第三种方式比前两种快百倍。<br></p>]]></description><link>https://zzs0.com/find-cha-kan-shan-chu-de-san-chong-fang-shi/</link><guid isPermaLink="false">62c2505a41802d000118e2bf</guid><dc:creator><![CDATA[MMA🐵JAZZ]]></dc:creator><pubDate>Mon, 04 Jul 2022 02:30:34 GMT</pubDate><content:encoded><![CDATA[<p>find 查看删除的三种方式，如删除当前目录下的TXT文件：</p><p>方法1：xargs rm -f</p><pre><code>find ./ -type f -name "*txt" |xargs rm -f</code></pre><p><br>方法2：-exec rm -f<br></p><pre><code>find ./ -type f -name "txt" -exec rm -f {} ;</code></pre><p><br>-exec命令是查找到的每个文件调用一次rm命令，因此速度最慢</p><p>方法3：-delete<br></p><pre><code>find ./ -type f -name "*txt" -delete</code></pre><p><br>如果一次删除大量文件，建议采用第三种方式。经测试在删除千万级文件时，第三种方式比前两种快百倍。<br></p>]]></content:encoded></item><item><title><![CDATA[mac定时执行任务]]></title><description><![CDATA[<h2 id="1-launchctl">1、launchctl</h2><blockquote>launchctl: 是一个统一的服务管理框架，可以启动、停止和管理守护进程、应用程序、进程和脚本等。</blockquote><blockquote>launchctl是通过配置文件来指定执行周期和任务的。</blockquote><h3 id="-plist-">配置文件（plist文件）</h3><p>launchctl 将根据plist文件的信息来启动任务。</p><h5 id="plist-">plist脚本一般存放在以下目录：</h5><ul><li><code>/Library/LaunchDaemons</code> --&gt;只要系统启动了，哪怕用户不登陆系统也会被执行</li><li><code>/Library/LaunchAgents</code> --&gt;当用户登陆系统后才会被执行</li></ul><h5 id="-plist--1">更多的plist存放目录：</h5><blockquote>~/Library/LaunchAgents 由用户自己定义的任务项</blockquote><blockquote>/Library/LaunchAgents 由管理员为用户定义的任务项</blockquote><blockquote>/Library/LaunchDaemons 由管理员定义的守护进程任务项</blockquote><blockquote>/System/Library/LaunchAgents 由Mac OS X为用户定义的任务项</blockquote><blockquote>/System/Library/LaunchDaemons 由Mac OS X定义的守护进程任务项</blockquote><h3 id="plist--1">plist部分参数说明：</h3><ul><li>Label：对应的需要保证全局唯一性；</li></ul>]]></description><link>https://zzs0.com/macding-shi-zhi-xing-ren-wu/</link><guid isPermaLink="false">62b17963fa39290001058074</guid><dc:creator><![CDATA[MMA🐵JAZZ]]></dc:creator><pubDate>Tue, 21 Jun 2022 08:01:28 GMT</pubDate><content:encoded><![CDATA[<h2 id="1-launchctl">1、launchctl</h2><blockquote>launchctl: 是一个统一的服务管理框架，可以启动、停止和管理守护进程、应用程序、进程和脚本等。</blockquote><blockquote>launchctl是通过配置文件来指定执行周期和任务的。</blockquote><h3 id="-plist-">配置文件（plist文件）</h3><p>launchctl 将根据plist文件的信息来启动任务。</p><h5 id="plist-">plist脚本一般存放在以下目录：</h5><ul><li><code>/Library/LaunchDaemons</code> --&gt;只要系统启动了，哪怕用户不登陆系统也会被执行</li><li><code>/Library/LaunchAgents</code> --&gt;当用户登陆系统后才会被执行</li></ul><h5 id="-plist--1">更多的plist存放目录：</h5><blockquote>~/Library/LaunchAgents 由用户自己定义的任务项</blockquote><blockquote>/Library/LaunchAgents 由管理员为用户定义的任务项</blockquote><blockquote>/Library/LaunchDaemons 由管理员定义的守护进程任务项</blockquote><blockquote>/System/Library/LaunchAgents 由Mac OS X为用户定义的任务项</blockquote><blockquote>/System/Library/LaunchDaemons 由Mac OS X定义的守护进程任务项</blockquote><h3 id="plist--1">plist部分参数说明：</h3><ul><li>Label：对应的需要保证全局唯一性；</li><li>Program：要运行的程序；</li><li>ProgramArguments：命令语句</li><li>StartCalendarInterval：在指定时间执行，类似crontab </li><li>StartInterval：循环执行时间，单位为秒</li><li>StandardInPath、StandardOutPath、StandardErrorPath：标准的输入输出错误文件，这里建议不要使用 .log 作为后缀，会打不开里面的信息。</li><li>定时启动任务时，如果涉及到网络，但是电脑处于睡眠状态，是执行不了的，这个时候，可以定时的启动屏幕就好了</li></ul><h2 id="-">任务相关命令</h2><pre><code class="language-php"># 加载任务, -w选项会将plist文件中无效的key覆盖掉，建议加上
$ launchctl load -w com.test.plist

# 删除任务
$ launchctl unload -w com.test.plist

# 查看任务列表, 使用 grep '任务部分名字' 过滤
$ launchctl list | grep 'test.demo'

# 开始任务
$ launchctl start  com.test.plist

# 结束任务
$ launchctl stop   com.test.plist
</code></pre><p><strong>注意：</strong><br>如果任务被修改了，那么必须先unload，然后重新load<br>start可以测试任务，这个是立即执行，不管时间到了没有<br>执行start和unload前，任务必须先load过，否则报错<br>stop可以停止任务</p><pre><code class="language-xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;
&lt;plist version="1.0"&gt;
&lt;dict&gt;
    &lt;!-- Label唯一的标识 --&gt;
    &lt;key&gt;Label&lt;/key&gt;
    &lt;string&gt;com.test&lt;/string&gt;
    &lt;!-- 指定要运行的脚本 --&gt;
    &lt;key&gt;ProgramArguments&lt;/key&gt;
    &lt;array&gt;
        &lt;string&gt;/Users/jamalping/Desktop/testShell.sh&lt;/string&gt;
    &lt;/array&gt;
    &lt;!-- 在指定时间运行 --&gt;
    &lt;key&gt;StartCalendarInterval&lt;/key&gt;
    &lt;dict&gt;
        &lt;key&gt;Minute&lt;/key&gt;
        &lt;integer&gt;1&lt;/integer&gt;
        &lt;key&gt;Hour&lt;/key&gt;
        &lt;integer&gt;0&lt;/integer&gt;
    &lt;/dict&gt;
    &lt;!-- 循环秒数执行 --&gt;
    &lt;key&gt;StartInterval&lt;/key&gt;
    &lt;integer&gt;3&lt;/integer&gt;
    &lt;key&gt;StandardOutPath&lt;/key&gt;
    &lt;!-- 标准输出文件 --&gt;
    &lt;string&gt;/Users/jamalping/Desktop/stdout&lt;/string&gt;
    &lt;!-- 标准错误输出文件，错误日志 --&gt;
    &lt;key&gt;StandardErrorPath&lt;/key&gt;
    &lt;string&gt;/Users/jamalping/Desktop/error.txt&lt;/string&gt;
&lt;/dict&gt;
&lt;/plist&gt;

</code></pre><ul><li>加载任务</li></ul><pre><code class="language-css">launchctl load -w com.test.plist 
</code></pre><ul><li>开始任务</li></ul><pre><code class="language-css">launchctl start -w com.test.plist 
</code></pre><p>权限问题解决：</p><pre><code class="language-bash">sudo chown root /Users/xxx/Library/LaunchAgents/sc.plist
sudo chgrp wheel /Users/xxx/Library/LaunchAgents/sc.plist</code></pre><p>循环执行示例：</p><pre><code class="language-xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;
&lt;plist version="1.0"&gt;
  &lt;dict&gt;
    &lt;!-- Label唯一的标识 --&gt;
    &lt;key&gt;Label&lt;/key&gt;
    &lt;string&gt;sc&lt;/string&gt;
    &lt;!-- 指定要运行的脚本 --&gt;
    &lt;key&gt;ProgramArguments&lt;/key&gt;
    &lt;array&gt;
      &lt;string&gt;/Users/xxx/Program/sc&lt;/string&gt;
    &lt;/array&gt;
    &lt;!-- 时间间隔（秒） --&gt;
    &lt;key&gt;StartInterval&lt;/key&gt;
    &lt;integer&gt;1200&lt;/integer&gt;
  &lt;/dict&gt;
&lt;/plist&gt;</code></pre>]]></content:encoded></item><item><title><![CDATA[通过winsw实现windows服务开机自启]]></title><description><![CDATA[<p>一、winsw （Windows Service Wrapper）<br>使用winsw，可以简单实现。winsw是用c#写的一个小工具。<br>所以运行需要”.NET framework“，现在Win10上都自带.NET framework4.0</p><p>原理其实是winsw.exe本身可以注册为windows服务，可以设置为自启动。<br>当他启动后，然后根据和此exe同名的xml文件中的配置，执行设置的命令，达到自启动的效果。</p><p>winsw的开源地址：<a href="https://github.com/winsw/winsw">https://github.com/winsw/winsw</a><br>目前稳定版本是v2.11.0，下载链接：<a href="https://github.com/winsw/winsw/releases/tag/v2.11.0">https://github.com/winsw/winsw/releases/tag/v2.11.0</a></p><p>二、查看.NET Framework版本<br>1、在地址栏上输入“C:</p>]]></description><link>https://zzs0.com/tong-guo-winswshi-xian-windowsfu-wu-kai-ji-zi-qi/</link><guid isPermaLink="false">62aad7d1a689410001750eb4</guid><dc:creator><![CDATA[MMA🐵JAZZ]]></dc:creator><pubDate>Thu, 16 Jun 2022 07:15:16 GMT</pubDate><content:encoded><![CDATA[<p>一、winsw （Windows Service Wrapper）<br>使用winsw，可以简单实现。winsw是用c#写的一个小工具。<br>所以运行需要”.NET framework“，现在Win10上都自带.NET framework4.0</p><p>原理其实是winsw.exe本身可以注册为windows服务，可以设置为自启动。<br>当他启动后，然后根据和此exe同名的xml文件中的配置，执行设置的命令，达到自启动的效果。</p><p>winsw的开源地址：<a href="https://github.com/winsw/winsw">https://github.com/winsw/winsw</a><br>目前稳定版本是v2.11.0，下载链接：<a href="https://github.com/winsw/winsw/releases/tag/v2.11.0">https://github.com/winsw/winsw/releases/tag/v2.11.0</a></p><p>二、查看.NET Framework版本<br>1、在地址栏上输入“C:\Windows\Microsoft.NET\Framework”，按回车键<br>2、可以看到.NET Framework版本。可以看到最高版本为4.0</p><p>三、修改及设置<br>1、把winsw.exe改名为有意义名称，比如apiServer.exe。<br>因为注册后服务启动的exe就是这个exe，所以修改后便于管理和识别。<br>修改sample-minimal.xml 为和exe同名文件，如apiServer.xml<br>把apiServer.exe和apiServer.xml放在和jar相同目录即可。</p><p>2、xml设置</p><!--kg-card-begin: markdown--><pre><code class="language-xml">&lt;service&gt;
  &lt;id&gt;apiServer&lt;/id&gt;
  &lt;name&gt;apiServer&lt;/name&gt;
  &lt;description&gt;ApiService&lt;/description&gt;
  &lt;startmode&gt;Automatic&lt;/startmode&gt;
  &lt;executable&gt;c:\frpc.exe&lt;/executable&gt;
  &lt;arguments&gt;-c c:\frpc.ini&lt;/arguments&gt;
&lt;/service&gt;
</code></pre>
<!--kg-card-end: markdown--><p>相关参数说明如下：</p><p>id：安装windows服务后的服务ID，必须是唯一的。<br>name：服务名称，也必须是唯一的。一般和id一致即可。<br>description：服务说明，可以使用中文，可做备注使用。<br>executable：执行的命令，比如启动springboot应用的命令java。<br>arguments：命令执行参数，比如 包路径，类路径等。<br>四、安装服务<br>以管理员身份执行cmd，切换到exe所在目录，执行如下命令即可。</p><p>apiServer.exe install</p><p><br>除install之外，还有如下命令：</p><p>uninstall：删除服务<br>start：启动服务<br>stop：停止服务<br>restart：重启服务<br>status：查看状态</p>]]></content:encoded></item><item><title><![CDATA[docker修改错误容器内文件（postgres）]]></title><description><![CDATA[<p>postgres遇到了连接数过多的问题，发现默认超级用户连接数只有3，并且修改的话需要修改配置文件。</p><p>由于当时启动的时候并没有挂载数据文件，所以修改只能进入容器内部修改，具体路径</p><p>/var/lib/postgresql/data/postgresql.conf</p><p>但是由于操作失误，造成普通用户连接数和超级用户连接数一样了，规定是超级用户连接数一定要小于普通用户连接数，所以docker不能启动了，就没办法进去修改文件了，所以采用以下办法。</p><p>先停止容器，然后将容器内文件复制出来，修改完后再复制回去</p><p>docker cp postgres:/var/lib/postgresql/data/postgresql.conf ./</p><p>docker cp ./postgresql.conf postgres:/var/lib/postgresql/data/postgresql.conf</p><p>然后启动容器就可以了</p>]]></description><link>https://zzs0.com/dockerxiu-gai-cuo-wu-rong-qi-nei-wen-jian-postgres/</link><guid isPermaLink="false">62a31a2c7e8e33000149eae5</guid><dc:creator><![CDATA[MMA🐵JAZZ]]></dc:creator><pubDate>Fri, 10 Jun 2022 10:22:32 GMT</pubDate><content:encoded><![CDATA[<p>postgres遇到了连接数过多的问题，发现默认超级用户连接数只有3，并且修改的话需要修改配置文件。</p><p>由于当时启动的时候并没有挂载数据文件，所以修改只能进入容器内部修改，具体路径</p><p>/var/lib/postgresql/data/postgresql.conf</p><p>但是由于操作失误，造成普通用户连接数和超级用户连接数一样了，规定是超级用户连接数一定要小于普通用户连接数，所以docker不能启动了，就没办法进去修改文件了，所以采用以下办法。</p><p>先停止容器，然后将容器内文件复制出来，修改完后再复制回去</p><p>docker cp postgres:/var/lib/postgresql/data/postgresql.conf ./</p><p>docker cp ./postgresql.conf postgres:/var/lib/postgresql/data/postgresql.conf</p><p>然后启动容器就可以了</p>]]></content:encoded></item><item><title><![CDATA[KMS激活]]></title><description><![CDATA[<p>各版本秘钥</p><!--kg-card-begin: markdown--><pre><code class="language-sh"># 设置秘钥
slmgr -ipk [key]
# 设置激活服务器
slmgr -skms [kms server]
# 激活
slmgr -ato
# 查看状态
slmgr /xpr</code></pre>
<!--kg-card-end: markdown--><p><strong>win7：</strong></p><p>企业版	33PXH-7Y6KF-2VJC9-XBBR8-HVTHH</p><p>旗舰版	W269N-WFGWX-YVC9B-4J6C9-T83GX</p><p><br></p><p><strong>win server 2019：</strong></p><p>Windows Server 2019 Datacenter    WMDGN-G9PQG-XVVXX-R3X43-63DFG</p><p>Windows Server 2019 Standard    N69G4-B89J2-4G8F4-WWYCC-J464C</p><p>Windows Server 2019 Essentials    WVDHN-86M7X-466 P 6-VHXV7-YY726</p><p><br></p><p><strong>win10 LTSC</strong></p><p>M7XTQ-FN8P6-TTKYV-9D4CC-J462D</p><p><br></p><p><strong>Windows 10密钥</strong></p><p>专业版：W269N-WFGWX-YVC9B-4J6C9-T83GX</p><p>企业版：NPPR9-FWDCX-D2C8J-H872K-2YT43</p>]]></description><link>https://zzs0.com/kmsji-huo/</link><guid isPermaLink="false">624bfd981bbb4400011227bd</guid><dc:creator><![CDATA[MMA🐵JAZZ]]></dc:creator><pubDate>Tue, 05 Apr 2022 08:31:04 GMT</pubDate><content:encoded><![CDATA[<p>各版本秘钥</p><!--kg-card-begin: markdown--><pre><code class="language-sh"># 设置秘钥
slmgr -ipk [key]
# 设置激活服务器
slmgr -skms [kms server]
# 激活
slmgr -ato
# 查看状态
slmgr /xpr</code></pre>
<!--kg-card-end: markdown--><p><strong>win7：</strong></p><p>企业版	33PXH-7Y6KF-2VJC9-XBBR8-HVTHH</p><p>旗舰版	W269N-WFGWX-YVC9B-4J6C9-T83GX</p><p><br></p><p><strong>win server 2019：</strong></p><p>Windows Server 2019 Datacenter    WMDGN-G9PQG-XVVXX-R3X43-63DFG</p><p>Windows Server 2019 Standard    N69G4-B89J2-4G8F4-WWYCC-J464C</p><p>Windows Server 2019 Essentials    WVDHN-86M7X-466 P 6-VHXV7-YY726</p><p><br></p><p><strong>win10 LTSC</strong></p><p>M7XTQ-FN8P6-TTKYV-9D4CC-J462D</p><p><br></p><p><strong>Windows 10密钥</strong></p><p>专业版：W269N-WFGWX-YVC9B-4J6C9-T83GX</p><p>企业版：NPPR9-FWDCX-D2C8J-H872K-2YT43</p><p>家庭版：TX9XD-98N7V-6WMQ6-BX7FG-H8Q99</p><p>教育版：NW6C2-QMPVW-D7KKK-3GKT6-VCFB2</p><p>专业版N：MH37W-N47XK-V7XM9-C7227-GCQG9</p><p>企业版N：DPH2V-TTNVB-4X9Q3-TJR4H-KHJW4</p><p>教育版N：2WH4N-8QGBV-H22JP-CT43Q-MDWWJ</p><p>企业版LSTB：WNMTR-4C88C-JK8YV-HQ7T2-76DF9</p><p>企业版LSTB N：2F77B-TNFGY-69QQF-B8YKP-D69TJ</p>]]></content:encoded></item><item><title><![CDATA[docker日志清理]]></title><description><![CDATA[<h4 id="1-">1.问题</h4><p>docker容器日志导致主机磁盘空间满了。docker logs -f container_name噼里啪啦一大堆，很占用空间，不用的日志可以清理掉了。</p><p>解决方法<br>2.1 找出Docker容器日志<br>在linux上，容器日志一般存放在/var/lib/docker/containers/container_id/下面，查看各个日志文件大小的脚本docker_log_size.sh，内容如下：</p><!--kg-card-begin: markdown--><pre><code class="language-sh">#!/bin/sh
 
echo &quot;======== docker containers logs file size ========&quot;  
 
logs=$(find /var/lib/docker/containers/ -name *-json.log)  
 
for log in</code></pre>]]></description><link>https://zzs0.com/dockerri-zhi-qing-li/</link><guid isPermaLink="false">6246a8546682d200019ac57d</guid><dc:creator><![CDATA[MMA🐵JAZZ]]></dc:creator><pubDate>Fri, 01 Apr 2022 08:10:48 GMT</pubDate><content:encoded><![CDATA[<h4 id="1-">1.问题</h4><p>docker容器日志导致主机磁盘空间满了。docker logs -f container_name噼里啪啦一大堆，很占用空间，不用的日志可以清理掉了。</p><p>解决方法<br>2.1 找出Docker容器日志<br>在linux上，容器日志一般存放在/var/lib/docker/containers/container_id/下面，查看各个日志文件大小的脚本docker_log_size.sh，内容如下：</p><!--kg-card-begin: markdown--><pre><code class="language-sh">#!/bin/sh
 
echo &quot;======== docker containers logs file size ========&quot;  
 
logs=$(find /var/lib/docker/containers/ -name *-json.log)  
 
for log in $logs  
        do  
             ls -lh $log   
        done  </code></pre>
<!--kg-card-end: markdown--><p>2.2 清理Docker容器日志（治标）<br>如果docker容器正在运行，那么使用rm -rf方式删除日志后，通过df -h会发现磁盘空间并没有释放。原因是在Linux或者Unix系统中，通过rm -rf或者文件管理器删除文件，将会从文件系统的目录结构上解除链接（unlink）。如果文件是被打开的（有一个进程正在使用），那么进程将仍然可以读取该文件，磁盘空间也一直被占用。正确姿势是cat /dev/null &gt; *-json.log，当然你也可以通过rm -rf删除后重启docker。接下来，提供一个日志清理脚本clean_docker_log.sh，内容如下：</p><!--kg-card-begin: markdown--><pre><code class="language-sh">#!/bin/sh
echo &quot;=================== start clean docker containers logs
==========================&quot; 
 
logs=$(find /var/lib/docker/containers/ -name *-json.log)
 
for log in $logs; 
do
    echo &quot;clean logs:&quot; 
    echo $log
    cat /dev/null&gt;$log
done
 
echo &quot;==================== end clean docker containers logs ==========================&quot;
 
echo `date`</code></pre>
<!--kg-card-end: markdown--><p>但是，这样清理之后，随着时间的推移，容器日志会像杂草一样，卷土重来。</p><p>计划任务，每天执行一次</p><p>2.3 设置Docker容器日志大小（治本）<br>设置一个容器服务的日志大小上限<br>上述方法，日志文件迟早又会涨回来。要从根本上解决问题，需要限制容器服务的日志大小上限。这个通过配置容器docker-compose的max-size选项来实现</p><!--kg-card-begin: markdown--><pre><code class="language-yaml">nginx: 
  image: nginx:1.12.1 
  restart: always 
  logging: 
    driver: “json-file” 
    options: 
      max-size: “5g” </code></pre>
<!--kg-card-end: markdown--><p>重启nginx容器之后，其日志文件的大小就被限制在5GB，再也不用担心了。</p><p>全局设置<br>新建/etc/docker/daemon.json，若有就不用新建了。添加log-dirver和log-opts参数，样例如下：</p><!--kg-card-begin: markdown--><pre><code class="language-sh"># vim /etc/docker/daemon.json
 
{
  &quot;registry-mirrors&quot;: [&quot;http://f613ce8f.m.daocloud.io&quot;],
  &quot;log-driver&quot;:&quot;json-file&quot;,
  &quot;log-opts&quot;: {&quot;max-size&quot;:&quot;500m&quot;, &quot;max-file&quot;:&quot;3&quot;}
}</code></pre>
<!--kg-card-end: markdown--><p><br>max-size=500m，意味着一个容器日志大小上限是500M，<br>max-file=3，意味着一个容器有三个日志，分别是id+.json、id+1.json、id+2.json。</p><p>重启docker守护进程</p><!--kg-card-begin: markdown--><pre><code class="language-sh">systemctl daemon-reload
systemctl restart docker</code></pre>
<!--kg-card-end: markdown--><p>注意：设置的日志大小，只对新建的容器有效。</p>]]></content:encoded></item><item><title><![CDATA[无需root卸载、恢复安卓自带软件]]></title><description><![CDATA[<!--kg-card-begin: markdown--><pre><code class="language-bash">#获取所有app的package列表
adb shell pm list packages

#获取当前打开的app的信息，这里面包含package名称
adb shell dumpsys window|findstr mCurrent

#不需要root进行卸载系统应用
adb shell pm uninstall -k --user 0 你需要卸载的app的package名称

#恢复卸载的系统应用
adb shell cmd package install-existing 你需要恢复的app的package名称
</code></pre>
<!--kg-card-end: markdown--><p>附口袋阅package名称：</p><p>1.浏览器com.android.browser<br>2.应用中心com.xy.appstore<br>3.口袋阅助手com.unisyou.ubackup<br>4.壁纸设置com.android.wallpaperpicker<br>5.QQ阅读com.yuewen.</p>]]></description><link>https://zzs0.com/wu-xu-rootxie-zai-hui-fu-an-zhuo-zi-dai-ruan-jian/</link><guid isPermaLink="false">618a15e81ca95f0001bbf83d</guid><dc:creator><![CDATA[MMA🐵JAZZ]]></dc:creator><pubDate>Tue, 09 Nov 2021 06:36:38 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><pre><code class="language-bash">#获取所有app的package列表
adb shell pm list packages

#获取当前打开的app的信息，这里面包含package名称
adb shell dumpsys window|findstr mCurrent

#不需要root进行卸载系统应用
adb shell pm uninstall -k --user 0 你需要卸载的app的package名称

#恢复卸载的系统应用
adb shell cmd package install-existing 你需要恢复的app的package名称
</code></pre>
<!--kg-card-end: markdown--><p>附口袋阅package名称：</p><p>1.浏览器com.android.browser<br>2.应用中心com.xy.appstore<br>3.口袋阅助手com.unisyou.ubackup<br>4.壁纸设置com.android.wallpaperpicker<br>5.QQ阅读com.yuewen.cooperate.ekreader</p>]]></content:encoded></item><item><title><![CDATA[Docker多架构镜像推送]]></title><description><![CDATA[<p>一、创建不同架构的镜像，可用名称或tag区分平台</p><!--kg-card-begin: markdown--><pre><code class="language-bash">author/image_name:amd64
author/image_name:arm64
</code></pre>
<!--kg-card-end: markdown--><p>将不同架构的镜像推送到hub，不然会出现no such manifest错误</p><p>二、创建合集maniferst</p><!--kg-card-begin: markdown--><pre><code class="language-bash">docker manifest create author/image_name:latest \
    author/image_name:amd64 \
    author/image_name:arm64 --amend
</code></pre>
<!--kg-card-end: markdown--><p>三、推送对应的manifest</p><!--kg-card-begin: markdown--><pre><code class="language-bash">docker manifest push author/image_name:latest
</code></pre>
<!--kg-card-end: markdown-->]]></description><link>https://zzs0.com/dockerduo-jia-gou-jing-xiang-tui-song/</link><guid isPermaLink="false">61694db273c495000113a8d5</guid><dc:creator><![CDATA[MMA🐵JAZZ]]></dc:creator><pubDate>Fri, 15 Oct 2021 09:52:18 GMT</pubDate><content:encoded><![CDATA[<p>一、创建不同架构的镜像，可用名称或tag区分平台</p><!--kg-card-begin: markdown--><pre><code class="language-bash">author/image_name:amd64
author/image_name:arm64
</code></pre>
<!--kg-card-end: markdown--><p>将不同架构的镜像推送到hub，不然会出现no such manifest错误</p><p>二、创建合集maniferst</p><!--kg-card-begin: markdown--><pre><code class="language-bash">docker manifest create author/image_name:latest \
    author/image_name:amd64 \
    author/image_name:arm64 --amend
</code></pre>
<!--kg-card-end: markdown--><p>三、推送对应的manifest</p><!--kg-card-begin: markdown--><pre><code class="language-bash">docker manifest push author/image_name:latest
</code></pre>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[rsync服务器间的文件同步]]></title><description><![CDATA[<p>服务器有 源服务器A 和 备份服务器B</p><p>两台服务器均安装rsync</p><p>配置文件/etc/rsyncd.conf:</p><pre><code>uid = 0
gid = 0
use chroot = no
max connections = 10

[rsyncd]
path = /pathyouwanttosync
ignore errors
read only = yes
list = no</code></pre><p>Ubuntu自带开启方法:</p><pre><code class="language-shell"># 开启功能
vim /etc/default/rsync
# 修改
RSYNC_ENABLE=true   #false改true
# 创建配置文件
vi /etc/rsyncd.conf
# 启动
/etc/init.d/rsync</code></pre>]]></description><link>https://zzs0.com/rsyncfu-wu-qi-jian-de-wen-jian-tong-bu/</link><guid isPermaLink="false">60516f29819dbd00010b4f6b</guid><dc:creator><![CDATA[MMA🐵JAZZ]]></dc:creator><pubDate>Wed, 17 Mar 2021 03:04:54 GMT</pubDate><content:encoded><![CDATA[<p>服务器有 源服务器A 和 备份服务器B</p><p>两台服务器均安装rsync</p><p>配置文件/etc/rsyncd.conf:</p><pre><code>uid = 0
gid = 0
use chroot = no
max connections = 10

[rsyncd]
path = /pathyouwanttosync
ignore errors
read only = yes
list = no</code></pre><p>Ubuntu自带开启方法:</p><pre><code class="language-shell"># 开启功能
vim /etc/default/rsync
# 修改
RSYNC_ENABLE=true   #false改true
# 创建配置文件
vi /etc/rsyncd.conf
# 启动
/etc/init.d/rsync start</code></pre><p>Debian需要安装:</p><pre><code># 安装
apt install -y rsync
# 创建配置文件
vi /etc/rsyncd.conf
# 启动
service rsync start</code></pre><p>安装好了之后使用crontab按需同步，同步脚本</p><p>其中ssh可以修改端口，下面的服务器都按需配置</p><pre><code class="language-shell">#!/usr/bin/expect
set timeout -1
spawn rsync -vzurto -e "ssh -p 220" --progress --delete \
	root@127.0.0.1::rsyncd /root/music
expect {
    "password" {send "DaiHome!23\r";}
    "yes/no" {send "yes\r";exp_continue}
}
expect eof
exit</code></pre>]]></content:encoded></item><item><title><![CDATA[反代/中转cloudflare的安全隐患与隐患利用]]></title><description><![CDATA[<blockquote>转载来自：<a href="https://notesail.com/posts/danger-of-cloudflare-transit.html">https://notesail.com/posts/danger-of-cloudflare-transit.html</a></blockquote><p>本文核心：不要直接中转或反代cloudflare！存在着被他人利用的风险，还有就是不要利用文章内容做坏事！</p><p>我发现出于各种目的，很多人喜欢用iptables或者是brook、socat等工具对cloudflare的端口进行中转或者是反代，但是这些工具都有一个共同的特点，不会检查传入的主机名（域名）就直接将流量转发给了cloudflare，这里存在着一个巨大的风险——他人<strong>只要知道了你反代/中转服务器的相应端口，那他只需要指定host与sni，就可以利用你的反代/中转服务器</strong>通过cloudflare与他自己的服务器进行数据交换。</p><blockquote><strong>补充 除了使用iptables，像是socat、brook等端口转发工具同样有被利用的风险，因为他们都没有检查传入的域名，如果真的有反代cloudflare的需求，请使用nginx并指定主机名。另外这篇文章仅出于折腾目的而写，无论是利用cloudflare来科学上网还是利用别人的服务器，都是不道德的。</strong></blockquote><p>出于学习的目的，我想对这个方案进行一下测试与利用，看看能否扫描出反代或是中转cloudflare的机器的相应端口，顺便练习一下shell脚本的编写，大概会实现下面两个功能：</p><ol><li>对指定ip的端口段进行扫描 (已经简单实现)</li></ol><p>适合用来找出一台机器上反代了cloudflare的端口（如商家将机器切分成nat出来销售，某些用户会用iptables反代cloudflare）</p><ol><li>对ip段的80/443端口进行扫描 (还没有实现)</li></ol><p>适合大范围查找反代了cloudflare进行建站的机器。</p>]]></description><link>https://zzs0.com/fan-dai-zhong-zhuan-cloudflarede-an-quan-yin-huan-yu-yin-huan-li-yong/</link><guid isPermaLink="false">5fc849a3074d9b0001d14ed4</guid><dc:creator><![CDATA[MMA🐵JAZZ]]></dc:creator><pubDate>Thu, 03 Dec 2020 02:14:10 GMT</pubDate><content:encoded><![CDATA[<blockquote>转载来自：<a href="https://notesail.com/posts/danger-of-cloudflare-transit.html">https://notesail.com/posts/danger-of-cloudflare-transit.html</a></blockquote><p>本文核心：不要直接中转或反代cloudflare！存在着被他人利用的风险，还有就是不要利用文章内容做坏事！</p><p>我发现出于各种目的，很多人喜欢用iptables或者是brook、socat等工具对cloudflare的端口进行中转或者是反代，但是这些工具都有一个共同的特点，不会检查传入的主机名（域名）就直接将流量转发给了cloudflare，这里存在着一个巨大的风险——他人<strong>只要知道了你反代/中转服务器的相应端口，那他只需要指定host与sni，就可以利用你的反代/中转服务器</strong>通过cloudflare与他自己的服务器进行数据交换。</p><blockquote><strong>补充 除了使用iptables，像是socat、brook等端口转发工具同样有被利用的风险，因为他们都没有检查传入的域名，如果真的有反代cloudflare的需求，请使用nginx并指定主机名。另外这篇文章仅出于折腾目的而写，无论是利用cloudflare来科学上网还是利用别人的服务器，都是不道德的。</strong></blockquote><p>出于学习的目的，我想对这个方案进行一下测试与利用，看看能否扫描出反代或是中转cloudflare的机器的相应端口，顺便练习一下shell脚本的编写，大概会实现下面两个功能：</p><ol><li>对指定ip的端口段进行扫描 (已经简单实现)</li></ol><p>适合用来找出一台机器上反代了cloudflare的端口（如商家将机器切分成nat出来销售，某些用户会用iptables反代cloudflare）</p><ol><li>对ip段的80/443端口进行扫描 (还没有实现)</li></ol><p>适合大范围查找反代了cloudflare进行建站的机器。</p><h2 id="-">可行性测试</h2><p>假设我们的域名</p><p>example.com使用了cloudflare，并点亮了橙色云朵（开启了cdn），那么我们可以访问，example.com/cdn-cgi/trace，如果可以正常访问，那么就意味着成功通过cloudflare访问到了这个机器。</p><p>我再找一台机器使用<a href="https://github.com/arloor/iptablesUtils">iptables端口转发脚本</a>对cloudflare进行中转。</p><!--kg-card-begin: markdown--><pre><code class="language-bash">wget --no-check-certificate -qO natcfg.sh https://raw.githubusercontent.com/arloor/iptablesUtils/master/natcfg.sh &amp;&amp; bash natcfg.sh
</code></pre>
<!--kg-card-end: markdown--><p>并添加如下中转</p><figure class="kg-card kg-image-card"><img src="https://img.aoyouer.com/images/2020/11/05/20201105191323.png#vwid=943&amp;vhei=390" class="kg-image" alt="设置中转" title="设置中转"></figure><p>之后我们尝试使用</p><p><a href="https://xn--ip-py2c473ae1v898c/">https://中转机器ip</a>:10086，发现如果没指明host是没办法访问的。</p><figure class="kg-card kg-image-card"><img src="https://img.aoyouer.com/images/2020/11/05/20201105191228.png#vwid=1431&amp;vhei=309" class="kg-image" alt="报错" title="报错"></figure><p>之后我们使用curl进行测试</p><p>如果是80端口，那么我们需要设置HEADER中的host</p><p><code>curl -H 'Host: 开启了CDN的域名' http://中转机ip:10087</code></p><figure class="kg-card kg-image-card"><img src="https://img.aoyouer.com/images/2020/11/05/20201105191811.png#vwid=1198&amp;vhei=315" class="kg-image" alt="curl检测http" title="curl检测http"></figure><p>但是对于https，因为host记录在header中，而https需要先进行tls握手，tls握手信息中并没有包含目标网站的主机名，所以需要再通过SNI协议来指明访问的主机名是什么。</p><p>如果我们不设置sni直接尝试通过 https访问10086端口，会返回错误 <em>curl: (35) error:1408F10B:SSL routines:ssl3_get_record:wrong version number</em></p><p>对于开启了https的端口(比如iptables转发的是cloudflare的ip的443端口)，可以使用这种方式，--resolve参数介绍如下</p><p><em>--resolve &lt;host:port:address[,address]...&gt; Resolve the host+port to this address</em></p><p>作用类似于修改了dns，将example.com:10086的请求导向了后面的中转机的ip:相同端口</p><p><code>curl --resolve 开启了cdn的域名:10086:中转机ip https://开启了cdn的域名:10086/cdn-cgi/trace</code></p><figure class="kg-card kg-image-card"><img src="https://img.aoyouer.com/images/2020/11/05/20201105193036.png#vwid=1401&amp;vhei=317" class="kg-image" alt="正确返回后的请求" title="正确返回后的请求"></figure><p>另外补充几条之后需要用到的curl参数</p><ul><li>curl -I 可以显示响应头，如果对于/cdn-cgi/trace的请求响应头是404，说明这机器反代的并不是cloudflare，200则代表是cloudflare。</li><li>--connect-timeout SECONDS 设置连接超时时间（连接超时指的是连不上服务器，比如域名无法解析的情况）</li><li>-m, --max-time SECONDS 设置请求超时的时间，如果连接上了，但是半天没有回复的时间</li><li>-s 不显示进度条信息</li><li>-w %{http_code}</li></ul><p>-w可以指定curl的输出，而我们只需要查看http状态码即可</p><ul><li>-o /dev/null 如果我们只要状态码，可以把原来的输出丢弃</li></ul><h2 id="shell-">shell脚本编写</h2><h3 id="-ip-">单ip端口段扫描</h3><p>当前脚本功能还是比较简单，只扫描某一指定ip的指定ip段，之后我考虑编写扫描ip段指定端口的脚本。或者加入多线程扫描。</p><pre><code class="language-bash">#!/bin/bash
#扫描使用iptables反代cloudflare的脚本
#该脚本用于对指定的一个ip的指定范围的端口进行扫描，寻找使用了iptables反代cloudflare的端口
TURL=''
HOST=''
SNI=''

read -p "请输入需要扫描的服务器ip:" server_ip
read -p "请输入扫描起始端口:" port_start
read -p "请输入扫描的结束端口:" port_end
#检测输入合法性
#declare -i port_start
#declare -i port_end
touch find_result.txt
if [ ${port_start} -gt ${port_end} ]; then
  echo "输入格式出错,起始端口应小于结束端口"
  exit 1
elif [ $port_end -gt 65535 ]; then
  echo "输入格式出错，端口过大"
  exit 1
fi
echo "开始对${server_ip}的${port_start}~${port_end}进行扫描" | tee -a find_result.txt
#循环扫描端口
find_count=0
for ((i = $port_start;i &lt;= $port_end;i++))
do
  echo -e "正在扫描端口$i 状态:\c"
  res=$(curl --connect-timeout 3 --max-time 2 -w %{http_code} -o /dev/null -s -I --resolve ${SNI}:${i}:${server_ip} https://${SNI}:${i}/cdn-cgi/trace)
  echo $res
  if [ $res == 200 ]; then
    let find_count++
    echo "找到可用端口${i}"  | tee -a find_result.txt
    #写入文件
  fi
  #curl -w %{http_code} -s -I --resolve ${SNI}:${i}:${server_ip} https://${SNI}:${i}/cdn-cgi/trace
done
echo "完成对${server_ip}的${port_start}~${port_end}进行扫描,共找到${find_count}个可用端口" | tee -a find_result.txt
</code></pre><h3 id="ip-">ip段扫描</h3><p>当前实现的脚本效率比较低，考虑到未来的优化方案，可以写成程序，先使用nmap筛选出80/443开放的ip，然后再使用多线程扫描，这样应该能快上很多。</p><p>这里首先用到了ipcalc这个程序，用来根据输入ip与掩码长度计算ip范围。效果如下</p><figure class="kg-card kg-image-card"><img src="https://img.aoyouer.com/images/2020/11/06/20201106091354.png#vwid=810&amp;vhei=223" class="kg-image" alt="image-20201106091353955" title="image-20201106091353955"></figure><pre><code class="language-shell">#!/bin/bash
#扫描使用iptables反代cloudflare的脚本
#该脚本用于对指定的ip段的80/443端口扫描查看是否反代了cloudflare
TURL=''
HOST=''
SNI=''

read -p "请输入需要扫描的ip:" server_ip
read -p "请输入掩码长度:" netmask
ipc_result=$(ipcalc -nb ${server_ip}/${netmask})
#起始ip地址
touch ipsg_scan.txt
# echo $ipc_result
host_min=$(echo "${ipc_result}" | awk '/HostMin/ {print $2}')
host_max=$(echo "${ipc_result}" | awk '/HostMax/ {print $2}')
host_num=$(echo "${ipc_result}" | awk '/Hosts\/Net/ {print $2}')
netmask=$(echo "${ipc_result}" | awk '/Netmask/ {print $2}')
host_address=$(echo "${ipc_result}" | awk '/Address/ {print $2}')
if [ $host_num -eq 1 ]; then
host_min=$host_address
host_max=$host_address
fi
# host_max=$(echo "${ipc_result}" | egrep '^HostMax:' | egrep '[0-9].*' -o)
echo "开始扫描，最小ip地址:${host_min},最大ip地址:${host_max},ip数量:${host_num}" | tee -a ipsg_scan.txt
find_count=0
find_port_count=0
#要将字符串列表转变为数组，只需要在前面加()，所以关键是将分隔符转变为空格分隔
scanip_arr=($(echo $host_min | tr '.' ' '))
# echo "ip arr: ${scanip_arr[*]}"
for ((i = 1;i &lt;= $host_num;i++))
do
scan_ip=$(echo ${scanip_arr[*]} | tr ' ' '.')
percent=$(echo "scale=3; $i / $host_num * 100" | bc)
#443端口扫描
echo -e "正在扫描ip:${scan_ip} 扫描百分比 ${percent}%\t443端口:\c"
res443=$(curl --connect-timeout 2 --max-time 3 -w %{http_code} -o /dev/null -s -I --resolve ${SNI}:443:${scan_ip} https://${SNI}:443/cdn-cgi/trace)
echo -e "$res443 80端口:\c"
#80端口扫描 为了加快扫描速度，可以不扫
res80=$(curl --connect-timeout 2 --max-time 2 -w %{http_code} -o /dev/null -s -I -H "Host: ${HOST}" http://${scan_ip}:80/cdn-cgi/trace)
echo $res80
if [ $res443 == 200 ] || [ $res80 == 200 ]; then
  let find_count++
  echo "找到可用ip:${scan_ip} 80端口状态:${res80} 443端口状态:${res443}"  | tee -a ipsg_scan.txt
  #写入文件
fi

#之后要对iparr进行增加
scanip_arr[3]=$((${scanip_arr[3]}+1))
if [ ${scanip_arr[3]} -gt 255 ]; then
  echo "C+1"
  scanip_arr[3]=1
  scanip_arr[2]=$((${scanip_arr[2]}+1))
fi
if [ ${scanip_arr[2]} -gt 255 ]; then
  echo "B+1"
  scanip_arr[2]=1
  scanip_arr[1]=$((${scanip_arr[1]}+1))
fi
if [ ${scanip_arr[1]} -gt 255 ]; then
  echo "A+1"
  scanip_arr[1]=1
  scanip_arr[0]=$((${scanip_arr[0]}+1))
fi
done
echo "完成扫描 共扫描了${host_num}个ip,找到${find_count}个可用ip" | tee -a ipsg_scan.txt</code></pre><h2 id="--1">利用</h2><p>之后我使用该脚本对国内某商家的nat母鸡ip进行了扫描...不得不说直接使用iptables反代cloudflare的人还不少。。。仅仅扫描了1000个端口就已经出现了好几个反代端口了</p><figure class="kg-card kg-image-card"><img src="https://img.aoyouer.com/images/2020/11/05/20201105213507.png#vwid=815&amp;vhei=578" class="kg-image" alt></figure><h2 id="--2">后记</h2><p>通过这一次实践，我再一次体会到了<strong>千万不要直接使用不检查主机名的工具直接中转或者反代cloudflare的ip</strong>，不然一不小心就会被别有用心之人利用，建议要反代cloudflare的话还是改用nginx，并设置好hostname，这样才不会被利用啊。</p><h2 id="--3">参考</h2><p><a href="https://hacksbrain.com/2018/08/27/testing-sni-enabled-servers-with-curl/">https://hacksbrain.com/2018/08/27/testing-sni-enabled-servers-with-curl/</a></p>]]></content:encoded></item><item><title><![CDATA[Docker安装nextcloud的注意事项]]></title><description><![CDATA[<p>由于ubuntu挂载的是Windows的文件夹，所以需要注意权限的问题，具体操作可以查看之前的文章</p><!--kg-card-begin: markdown--><h4 id="1">1.挂载目录</h4>
<h5 id>手动挂载文件系统指定权限(特殊字符要\转义）</h5>
<pre><code class="language-bash">mount -t cifs -o user=user,password=pass,iocharset=utf8,dir_mode=0777,file_mode=0777 //192.168.2.2/windows_dir /mount_point
</code></pre>
<h5 id>开机自动挂载（特殊字符不需要转义）</h5>
<pre><code class="language-bash">//192.168.2.2/share /root/share cifs rw,user=user,password=pass,iocharset=utf8,dir_</code></pre>]]></description><link>https://zzs0.com/dockeran-zhuang-nextcloudde-zhu-yi-shi-xiang/</link><guid isPermaLink="false">5f98e594014f010001ba8fa0</guid><dc:creator><![CDATA[MMA🐵JAZZ]]></dc:creator><pubDate>Wed, 28 Oct 2020 03:33:41 GMT</pubDate><content:encoded><![CDATA[<p>由于ubuntu挂载的是Windows的文件夹，所以需要注意权限的问题，具体操作可以查看之前的文章</p><!--kg-card-begin: markdown--><h4 id="1">1.挂载目录</h4>
<h5 id>手动挂载文件系统指定权限(特殊字符要\转义）</h5>
<pre><code class="language-bash">mount -t cifs -o user=user,password=pass,iocharset=utf8,dir_mode=0777,file_mode=0777 //192.168.2.2/windows_dir /mount_point
</code></pre>
<h5 id>开机自动挂载（特殊字符不需要转义）</h5>
<pre><code class="language-bash">//192.168.2.2/share /root/share cifs rw,user=user,password=pass,iocharset=utf8,dir_mode=0777,file_mode=0777 0 0
</code></pre>
<h4 id="2docker">2.docker安装</h4>
<h4 id="3docker">3.修改docker内的文件读取权限</h4>
<pre><code class="language-bash">docker exec -it [container] /bin/bash
sed -i &quot;s/deb.debian.org/mirrors.aliyun.com/g
apt update &amp;&amp; apt install vim
vi config/config.php
# 添加
'check_data_directory_permissions' =&gt; false
</code></pre>
<h4 id="4">4.添加域名，同步</h4>
<pre><code class="language-bash">./utils
</code></pre>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[HyperV宿主机与虚拟机共享文件夹]]></title><description><![CDATA[<p>宿主机是win server 2019，虚拟机一台win10，一台ubuntu</p><p>宿主机win server 2019开启smb服务，然后重启，之后在网络共享中心开启所有的网络共享，接着去文件夹属性打开共享，可以单独建一个账号用于共享文件夹</p><p>win10也打开网络共享与发现，然后映射网络驱动器，就可以看到宿主机的共享文件夹</p><p>ubuntu的配置是挂载网络文件夹，需要指定权限，不然后期docker会访问不了</p><!--kg-card-begin: markdown--><pre><code>vi /etc/fstab
# 添加
//192.168.2.2/share /root/share cifs rw,user=user,password=pass,iocharset=utf8,dir_mode=0777,file_mode=0777 0 0
</code></pre>
<!--kg-card-end: markdown-->]]></description><link>https://zzs0.com/hypervsu-zhu-ji-yu-xu-ni-ji-gong-xiang-wen-jian-jia/</link><guid isPermaLink="false">5f98d0f8014f010001ba8f7f</guid><dc:creator><![CDATA[MMA🐵JAZZ]]></dc:creator><pubDate>Wed, 28 Oct 2020 03:28:49 GMT</pubDate><content:encoded><![CDATA[<p>宿主机是win server 2019，虚拟机一台win10，一台ubuntu</p><p>宿主机win server 2019开启smb服务，然后重启，之后在网络共享中心开启所有的网络共享，接着去文件夹属性打开共享，可以单独建一个账号用于共享文件夹</p><p>win10也打开网络共享与发现，然后映射网络驱动器，就可以看到宿主机的共享文件夹</p><p>ubuntu的配置是挂载网络文件夹，需要指定权限，不然后期docker会访问不了</p><!--kg-card-begin: markdown--><pre><code>vi /etc/fstab
# 添加
//192.168.2.2/share /root/share cifs rw,user=user,password=pass,iocharset=utf8,dir_mode=0777,file_mode=0777 0 0
</code></pre>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>