std::forward_list 简介

std::forward_list 为 C++ 11 STL 的 单向 链表:

  • 仅记录了首指针,未记录尾指针和链表长度,即无 push_backsize 方法。
  • 相比 std::list (双向链表,以下简化为 list
    • 节约内存空间
    • 仅能 顺序访问 ,无法 倒序访问
    • forward_list::sort 时间复杂度 O(n log n) ,但效率不如 list::sort ,尤其链表包含大量元素时。

forward_listlist 大部分方法相同,这里仅介绍 forward_list 不具备的能力。

顺序插入

因无 forward_list::push_back 方法,顺序插入 forward_list 一组元素得依靠调用者 自行 保存尾指针。

forward_list<int> fl;
auto iter = fl.before_begin();

for (int i = 0; i < 9; ++i) {
	iter = fl.insert_after(iter, i);
}

before_begin 返回首元素之前的元素(placeholder)。该元素实际不存在,访问它将导致未定义行为。

顺序复制

  • back_inserter 返回的 std::back_insert_iterator 要求容器实现了 push_back 方法。
  • inserter 返回的 std::insert_iterator 要求容器实现了 insert 方法。

显然,两者皆不适用于 forward_list ,然 inserter 最接近:

通过 LIEF 修改 ELF 解决 glibc 兼容性问题

数月前,我读了 Linux 修改 ELF 解决 glibc 兼容性问题 ,颇受启发,但暂无用武之地。

最近,我遇到了几乎一样的问题,即 clock_gettime 兼容性。

最小化问题

为了将问题最小化,这里我以 hello.c 模拟该问题:

#include <stdio.h>
#include <time.h>

int main() {
    struct timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);
    printf("%lu, %ld\n", ts.tv_sec, ts.tv_nsec);
    return 0;
}

在 Ubuntu 20.04 中,用系统内置 GCC 9.3.0 构建它:

gcc -fno-stack-protector -o hello hello.c -s
  • -fno-stack-protector : 禁用 stack 保护特性。目的为最小化未定义符号,最小化问题场景。
  • -s : 除去调试相关符号,目的同上。

通过 readelf -sV hello 展示其符号:

Symbol table '.dynsym' contains 8 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     .....
     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND clock_gettime@GLIBC_2.17 (2)
     3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.2.5 (3)
     ......

Version symbols section '.gnu.version' contains 8 entries:
 Addr: 0x0000000000000526  Offset: 0x000526  Link: 6 (.dynsym)
  000:   0 (*local*)       0 (*local*)       2 (GLIBC_2.17)    3 (GLIBC_2.2.5)
  ......

Version needs section '.gnu.version_r' contains 1 entry:
 Addr: 0x0000000000000538  Offset: 0x000538  Link: 7 (.dynstr)
  000000: Version: 1  File: libc.so.6  Cnt: 2
  0x0010:   Name: GLIBC_2.2.5  Flags: none  Version: 3
  0x0020:   Name: GLIBC_2.17  Flags: none  Version: 2

问题在于修改 .gnu.version_r 段偏移 0x0020 的相关值。回顾 Elfxx_Vernaux 结构:

CentOS 8 上安装 LXC

一、安装 LXC 包

yum install -y epel-release
yum update -y
yum install -y lxc lxc-devel lxc-templates dnsmasq iptables debootstrap

安装 LXC 模板

yum install -y gcc make
wget -O- https://linuxcontainers.org/downloads/lxc/lxc-templates-3.0.4.tar.gz | tar zx
cd lxc-templates-3.0.4
./configure --prefix=/usr --localstatedir=/var
make install
  • 虽然 lxc-templates 包,但该包未包含 Ubuntu 容器模板。故还须从其源码安装。
  • lxc-templates-3.0.4 并不需要编译任何 C 程序,但 configure 将检查 gcc。故须安装 gcc
  • 安装模板后,若不需要 gccmake ,则可自行 卸载

二、配置 LXC 网络

LXC 存在 3 种网络:

Fail2Ban 简介 (一)

Fail2Ban 是入侵检测软件框架,保护计算机免受暴力破解(brute-force attack)。以 Python 语言编写,能运行于具有包(packet)控制或防火墙的 POSIX 系统,如 iptables 或 TCP Wrapper.

鉴于互联网针对 VPS 暴力破解 SSH 越来越频繁,以下以 Ubuntu 为例,介绍如何利用 Fail2Ban 有效禁止 SSH 破解。

一、安装

sudo apt-get install -y fail2ban

二、配置

Fail2Ban 配置文件格式 INI,存于 /etc/fail2ban 目录:

  • fail2ban.conf : fail2ban 程序运行的日志和数据库等参数。
  • jail.conf : 禁止(ban)相关参数。
  • filter.d/* : jail.conf 中涉及“节”(section,如 [sshd] )的过滤器,由正则表达式构成。
  • action.d/* : jail.conf 中涉及“节”(section,如 [sshd] )的处理器。

它们皆为安装文件,直接修改将导致后续升级 无法自动合并 配置文件。Fail2Ban 提供了自定义配置文件的机制:

  • fail2ban.conf 可依此通过 fail2ban.d/*fail2ban.local 来重定义相关选项。
  • jail.conf 可依此通过 jail.d/*jail.local 来重定义相关选项。

默认安装,/etc/fail2ban/jail.d/defaults-debian.conf 已启用 sshd 的 jail

如何导入 Ubuntu 重复 root 卷组

场景

  • 某云平台的 Ubuntu 虚拟机运行中突遇挂起,重启时挂起于某阶段,且无法进入恢复模式。
  • 因该云平台限制或问题,无法通过 Ubuntu 安装 ISO 引导该虚拟机。
  • 该虚拟机的 root 分区位于 LVM 卷组上。

当时,基本思路为挂载问题虚拟机的虚拟盘至新虚拟机,通过后者导入原虚拟盘的卷组,从而备份出重要数据。

然而,恰好该云平台仅有该虚拟机的原始模板,新实例的虚拟盘与旧盘:

  • PV UUID 重复
  • VG UUID 和名称重复

导致无法激活旧卷组。

办法

以下以 VirtualBox 安装 Ubuntu 20.04 虚拟机,克隆其系统盘为新虚拟盘,并将新盘加入该虚拟机来模拟场景。

启动系统

启动虚拟机将遇到 重复 PV 错误:

/images/boot-focal-duplicate-root-vg.png

进入 initramfs shell ,为了避免激活 root 卷组失败,暂时删除 /dev/sdb

echo 1 > /sys/block/sdb/device/delete
vgchange -ay
exit

将正常进入系统。

扫描 /dev/sdb

登录系统,切换 root 用户, 重新扫密 /dev/sdb

LXD简介(一)

LXD 是基于LXC容器的管理程序(hypervisor),它由开发 Ubuntu 的公司 Canonical 创建和维护。

它由3个组建构成:

  • lxd :系统守护进程,它导出能被本地和网络访问的 RESTful API
  • lxc :客户端命令行,它能跨网络管理多个容器主机。
  • nova-compute-lxd : OpenStack Nova 插件,它使 OpenStack 如虚拟机一般,管理容器。

一、安装

因 Ubuntu 16.04 LXD 2.x 和 Ubuntu 18.04 LXD 3.x 版本都较旧,且 Ubuntu 20.04 放弃 apt 安装 LXD 。

请据 Snap简介 安装 LXD

为避免每次 sudo lxc ,可将 lxd 组加入当前(非root)用户的附加组:

sudo usermod -aG lxd $USER

二、初始化

sudo lxd init

输出:

Would you like to use LXD clustering? (yes/no) [default=no]:

# 配置存储池
Do you want to configure a new storage pool? (yes/no) [default=yes]:
Name of the new storage pool [default=default]:
Name of the storage backend to use (btrfs, dir, lvm, zfs, ceph) [default=zfs]: dir

Would you like to connect to a MAAS server? (yes/no) [default=no]:

# 创建虚拟网络
Would you like to create a new local network bridge? (yes/no) [default=yes]:
What should the new bridge be called? [default=lxdbr0]:
What IPv4 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]:
What IPv6 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]:

# LXD 服务的网络配置
Would you like LXD to be available over the network? (yes/no) [default=no]: yes
Address to bind LXD to (not including port) [default=all]:
Port to bind LXD to [default=8443]:
Trust password for new clients:

参看: How to install LXD on Ubuntu