Avalonia使用备忘

安装 模板 可以安装一些Avalonia的dotnet模板 dotnet new install Templates.Prism.Avalonia dotnet new install Avalonia.Templates IDE插件 Rider里面安装插件 AvaloniaRider VisualStudio安装插件 Avalonia for Visual Studio Avalonia 中的一些特性 Binding $parent 您可以使用$parent符号绑定到目标在逻辑上的父级: <Button DockPanel.Dock="Bottom" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" x:CompileBindings="False" Command="{Binding $parent[Window].DataContext.AddItem}">Add Item </Button> <Border Tag="Hello World!"> <TextBlock Text="{Binding $parent.Tag}"/> </Border> 也可以通过在$parent符号添加索引器绑定到父控件的父控件: <Border Tag="Hello World!"> <Border> <TextBlock Text="{Binding $parent[1].Tag}"/> </Border> </Border> 索引器从0开始,因此$parent[0]等同于$parent。 还可以按类型绑定到祖先: <Border Tag="Hello World!"> <Decorator> <TextBlock Text="{Binding $parent[Border].Tag}"/> </Decorator> </Border> 最后,您可以组合索引器和类型: <Border Tag="Hello World!"> <Border> <Decorator> <TextBlock Text="{Binding $parent[Border;1].Tag}"/> </Decorator> </Border> </Border> 如果需要在祖先类型中包含XAML命名空间,一般使用:字符: ...

2023-07-31 · 8 分钟 · czyt

Buf使用备忘

Buf 工具针对于Schema驱动、基于 Protobuf 的 API 开发,为服务发布者和服务客户端提供可靠和更好的用户体验。简化了您的 Protobuf 管理策略,以便您可以专注于重要的事情。 下载安装 可以直接去buf的GitHub的release 页面下载,其他的安装方式参考官方文档 使用 三个yaml文件 初次接触buf项目的时候,有个疑问就是buf项目中buf.yaml buf.gen.yaml buf.work.yaml这个三个文件的区别和用途。下面是简单的一个表,列出了三个文件的区别: 文件名 文件位置 说明 buf.yaml 每个proto模块定义的根目录 buf.yaml 配置的位置告诉 buf 在哪里搜索 .proto 文件,模块的依赖项以及如何处理导入 buf.gen.yaml 一般放在仓库的根目录 文件控制 buf generate 命令如何针对任何输入执行 protoc 插件 buf.work.yaml 一般放在仓库的根目录 定义项目需要哪些proto模块 示例目录结构: . ├── buf.gen.yaml ├── buf.work.yaml ├── proto │ ├── acme │ │ └── weather │ │ └── v1 │ │ └── weather.proto │ └── buf.yaml └── vendor └── protoc-gen-validate ├── buf.yaml └── validate └── validate.proto 一个buf.yaml 的样例,可以通过buf mod init来创建: ...

2023-07-29 · 2 分钟 · czyt

浅析Jetbrains的产品版本和更新API设计

接口分析 单个产品信息接口 首先我们通过http抓包来看DataGrip这个产品查询接口,访问的接口地址为下面这个地址 https://data.services.jetbrains.com/products?code=DG&release.type=eap,rc,release&fields=distributions,link,name,releases&_=1690557030459 从接口上我们能看到有下面几个方面: graphql风格接口设计。 支持产品代码、软件包通道、软件平台的筛选。主要有下面几个: 平台 说明 Windows linux windowsZip windows压缩包 windowsARM64 mac macM1 该接口返回信息如下: { "DG": [ { "date": "2023-07-20", "type": "release", "downloads": { "linuxARM64": { "link": "https://download.jetbrains.com/datagrip/datagrip-2023.2-aarch64.tar.gz", "size": 570768510, "checksumLink": "https://download.jetbrains.com/datagrip/datagrip-2023.2-aarch64.tar.gz.sha256" }, "linux": { "link": "https://download.jetbrains.com/datagrip/datagrip-2023.2.tar.gz", "size": 569402212, "checksumLink": "https://download.jetbrains.com/datagrip/datagrip-2023.2.tar.gz.sha256" }, "thirdPartyLibrariesJson": { "link": "https://resources.jetbrains.com/storage/third-party-libraries/datagrip/datagrip-2023.2-third-party-libraries.json", "size": 62706, "checksumLink": "https://resources.jetbrains.com/storage/third-party-libraries/datagrip/datagrip-2023.2-third-party-libraries.json.sha256" }, "windows": { "link": "https://download.jetbrains.com/datagrip/datagrip-2023.2.exe", "size": 447884488, "checksumLink": "https://download.jetbrains.com/datagrip/datagrip-2023.2.exe.sha256" }, "windowsZip": { "link": "https://download.jetbrains.com/datagrip/datagrip-2023.2.win.zip", "size": 566939835, "checksumLink": "https://download.jetbrains.com/datagrip/datagrip-2023.2.win.zip.sha256" }, "windowsARM64": { "link": "https://download.jetbrains.com/datagrip/datagrip-2023.2-aarch64.exe", "size": 430945096, "checksumLink": "https://download.jetbrains.com/datagrip/datagrip-2023.2-aarch64.exe.sha256" }, "mac": { "link": "https://download.jetbrains.com/datagrip/datagrip-2023.2.dmg", "size": 542649736, "checksumLink": "https://download.jetbrains.com/datagrip/datagrip-2023.2.dmg.sha256" }, "macM1": { "link": "https://download.jetbrains.com/datagrip/datagrip-2023.2-aarch64.dmg", "size": 534462645, "checksumLink": "https://download.jetbrains.com/datagrip/datagrip-2023.2-aarch64.dmg.sha256" } }, "patches": { "win": [ { "fromBuild": "231.9011.35", "link": "https://download.jetbrains.com/datagrip/DB-231.9011.35-232.8660.111-patch-win.jar", "size": 405126814, "checksumLink": "https://download.jetbrains.com/datagrip/DB-231.9011.35-232.8660.111-patch-win.jar.sha256" }, { "fromBuild": "232.8660.88", "link": "https://download.jetbrains.com/datagrip/DB-232.8660.88-232.8660.111-patch-win.jar", "size": 25446054, "checksumLink": "https://download.jetbrains.com/datagrip/DB-232.8660.88-232.8660.111-patch-win.jar.sha256" } ], "mac": [ { "fromBuild": "231.9011.35", "link": "https://download.jetbrains.com/datagrip/DB-231.9011.35-232.8660.111-patch-mac.jar", "size": 386287057, "checksumLink": "https://download.jetbrains.com/datagrip/DB-231.9011.35-232.8660.111-patch-mac.jar.sha256" }, { "fromBuild": "232.8660.88", "link": "https://download.jetbrains.com/datagrip/DB-232.8660.88-232.8660.111-patch-mac.jar", "size": 24338594, "checksumLink": "https://download.jetbrains.com/datagrip/DB-232.8660.88-232.8660.111-patch-mac.jar.sha256" } ], "unix": [ { "fromBuild": "231.9011.35", "link": "https://download.jetbrains.com/datagrip/DB-231.9011.35-232.8660.111-patch-unix.jar", "size": 402009513, "checksumLink": "https://download.jetbrains.com/datagrip/DB-231.9011.35-232.8660.111-patch-unix.jar.sha256" }, { "fromBuild": "232.8660.88", "link": "https://download.jetbrains.com/datagrip/DB-232.8660.88-232.8660.111-patch-unix.jar", "size": 23828783, "checksumLink": "https://download.jetbrains.com/datagrip/DB-232.8660.88-232.8660.111-patch-unix.jar.sha256" } ] }, "notesLink": "https://www.jetbrains.com/datagrip/whatsnew/", "licenseRequired": true, "version": "2023.2", "majorVersion": "2023.2", "build": "232.8660.111", "whatsnew": "<img src=\"https://blog.jetbrains.com/wp-content/uploads/2023/07/updatedialog_600x130_DataGrip-2x-6.png\" alt=\"DataGrip 2023.2 released\" width=\"635\" border=\"0\"> \n<p>To learn more about new features and all the other improvements introduced in version 2023.2 please visit our <a href=\"https://www.jetbrains.com/datagrip/whatsnew/\">What's New page</a>.</p> \n<p></p> \n<h3>User Interface</h3> \n<ul> \n <li>New UI: The toolbar icons have been moved to the header:</li> \n</ul> \n<img class=\"alignnone size-large wp-image-123893\" src=\"https://blog.jetbrains.com/wp-content/uploads/2023/07/New-UI-toolbar-default.png\" alt=\"\" width=\"635\" height=\"\" border=\"0\">\n<p></p> \n<ul> \n <li>Improved main toolbar customization</li> \n <li>Light theme with light header in the new UI</li> \n <li>Colored project headers in the new UI</li> \n <li>New UI for schema migration dialog</li> \n</ul> \n<h3>Artificial Intelligence - Limited access</h3> \n<ul> \n <li>AI Assistant (Beta)</li> \n <li><i>AI Actions</i> submenu</li> \n</ul> \n<img class=\"alignnone size-large wp-image-123893\" src=\"https://blog.jetbrains.com/wp-content/uploads/2023/07/AI.png\" alt=\"\" width=\"635\" height=\"\" border=\"0\">\n<p></p> \n<h3>Connectivity</h3> \n<ul> \n <li>[Redis] Support for Redis Cluster</li> \n</ul> \n<img class=\"alignnone size-large wp-image-123893\" src=\"https://blog.jetbrains.com/wp-content/uploads/2023/07/image-11.png\" alt=\"\" width=\"635\" height=\"\" border=\"0\">\n<p></p> \n<ul> \n <li>[Redshift] Support for external databases and datashares</li> \n <li>More options for connecting with SSL certificates</li> \n <li>HTTP proxy</li> \n <li>Time stamp of the last refresh</li> \n</ul> \n<h3>Data editor</h3> \n<ul> \n <li>Time zones</li> \n</ul> \n<img class=\"alignnone size-large wp-image-123893\" src=\"https://blog.jetbrains.com/wp-content/uploads/2023/07/timeZones-2.png\" alt=\"\" width=\"635\" height=\"\" border=\"0\">\n<p></p> \n<ul> \n <li>Preview in settings</li> \n <li><i>Show all columns</i> action to help you find any columns that you may have hidden before</li> \n</ul> \n<h3>Navigation</h3> \n<ul> \n <li>Text search in <i>Search Everywhere</i></li> \n</ul> \n<img class=\"alignnone size-large wp-image-123893\" src=\"https://blog.jetbrains.com/wp-content/uploads/2023/07/TextSearch.png\" alt=\"\" width=\"635\" height=\"\" border=\"0\">\n<p></p> \n<h3>Coding assistance</h3> \n<ul> \n <li>New settings for qualifying objects</li> \n</ul> \n<img class=\"alignnone size-large wp-image-123893\" src=\"https://blog.jetbrains.com/wp-content/uploads/2023/07/Qualification.png\" alt=\"\" width=\"635\" height=\"\" border=\"0\">\n<p></p> \n<ul> \n <li>Syntax highlighting in inspection descriptions</li> \n</ul> \n<h3><i>Files</i> tool window</h3> \n<ul> \n <li>Sort by modification time</li> \n</ul> \n<img class=\"alignnone size-large wp-image-123893\" src=\"https://blog.jetbrains.com/wp-content/uploads/2023/07/SortByTime-1.png\" alt=\"\" width=\"635\" height=\"\" border=\"0\">\n<p></p> \n<ul> \n <li>Open folders with a single click</li> \n <li>Hiding scratches and consoles</li> \n</ul> \n<h3>Other</h3> \n<ul> \n <li>WSL support for dump tools</li> \n <li><i>Modify</i> UI: List of objects of the same kind</li> \n</ul> \n<img class=\"alignnone size-large wp-image-123893\" src=\"https://blog.jetbrains.com/wp-content/uploads/2023/07/Modify.png\" alt=\"\" width=\"635\" height=\"\" border=\"0\">\n<p></p>", "uninstallFeedbackLinks": { "linuxARM64": "https://www.jetbrains.com/datagrip/uninstall/?edition=2023.2", "windowsJBR8": "https://www.jetbrains.com/datagrip/uninstall/?edition=2023.2", "windowsZipJBR8": "https://www.jetbrains.com/datagrip/uninstall/?edition=2023.2", "linux": "https://www.jetbrains.com/datagrip/uninstall/?edition=2023.2", "thirdPartyLibrariesJson": "https://www.jetbrains.com/datagrip/uninstall/?edition=2023.2", "windows": "https://www.jetbrains.com/datagrip/uninstall/?edition=2023.2", "windowsZip": "https://www.jetbrains.com/datagrip/uninstall/?edition=2023.2", "windowsARM64": "https://www.jetbrains.com/datagrip/uninstall/?edition=2023.2", "linuxJBR8": "https://www.jetbrains.com/datagrip/uninstall/?edition=2023.2", "mac": "https://www.jetbrains.com/datagrip/uninstall/?edition=2023.2", "macJBR8": "https://www.jetbrains.com/datagrip/uninstall/?edition=2023.2", "macM1": "https://www.jetbrains.com/datagrip/uninstall/?edition=2023.2" }, "printableReleaseType": null } ] } 从返回上看,返回记录内容主要有那么几个方面: ...

2023-07-28 · 5 分钟 · czyt

Golang高效解码xml文件

xml处理需要引用encoding/xml包.一般推荐使用 xml.Decoder 替代 xml.Unmarshal。 xml.Decoder 是一个流式 XML 解码器,它可以边读取边解码,而不需要将整个 XML 文档加载到内存中。相比之下,xm1.Unmarshal 会将整个 XML 文档加载到内存中然后再进行解码。因此,对于大型 XML 文件,使用xml.Decoder 可以节省内存并提高性能。 小的Xml文件 下面是一个例子 package main import ( "encoding/xml" "os" "testing" ) type UserData struct { Name string `xml:"name"` Age int32 `xml:"age"` } type Pocket struct { Data []UserData `xml:"users"` } func TestXmlDecode(t *testing.T) { file, err := os.Open("testdata/userdata.xml") if err != nil { t.Fatal(err) } var pocket Pocket if err := xml.NewDecoder(file).Decode(&pocket); err != nil { t.Fatal(err) } t.Log(pocket) } func TestXmlEncode(t *testing.T) { pocket := Pocket{Data: []UserData{ {Name: "czyt", Age: 20}, {Name: "jone", Age: 12}, {Name: "jack", Age: 30}, }} file, err := os.OpenFile("testdata/userdata.xml", os.O_RDWR|os.O_CREATE, 0755) if err != nil { t.Fatal(err) } if err := xml.NewEncoder(file).Encode(pocket); err != nil { t.Fatal(err) } } 大的文件xml文件 ​ 在处理大的xml文件,推荐开启 xml.Decoder 的 strict 模式。在创建xml.Decoder 对象时,可以设置其 strict 字段为false,以允许解码器在遇到无法解析的 XML 特性时继续运行。这可以提高对于大型 XML 文件的容错能力。 ...

2023-07-26 · 2 分钟 · czyt

使用C#以编程方式切换Windows专注模式

缘起 最近需要以编程方式调用windows api实现windows10专注模式的切换,但是Google一圈,没有现成代码。找到的相关帖子要么是cpp的要么是rust的,而且是undocument的Windows api。 Csharp调用 以下是完整代码 public static class FocusAssistToogle { private const string NtdllDlDll = "ntdll.dll"; private const uint DataBufferSize = 4; private static readonly byte[] DisableDataBuf = { 0x00, 0x00, 0x00, 0x00 }; // 01仅优先通知 02 仅限闹钟 private static readonly byte[] EnableDataBuf = { 0x02, 0x00, 0x00, 0x00 }; [DllImport(NtdllDlDll, SetLastError = true)] private static extern int ZwUpdateWnfStateData( ref WnfSWnfStateName sWnfStateName, byte[] buffer, uint bufferSize, IntPtr previousStateData, IntPtr currentStateData, uint previousStateDataSize, uint currentStateDataSize); [StructLayout(LayoutKind.Sequential)] private struct WnfSWnfStateName { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public uint[] Data; } private static WnfSWnfStateName _wnfSWnfShelQuietMomentShellModeChanged = new WnfSWnfStateName { Data = new uint[] { 0xa3bf5075, 0xd83063e } }; public static bool EnableFocusMode() { int result = ZwUpdateWnfStateData(ref _wnfSWnfShelQuietMomentShellModeChanged, EnableDataBuf, DataBufferSize, IntPtr.Zero, IntPtr.Zero, 0, 0); return result == 0; } public static bool DisableFocusMode() { int result = ZwUpdateWnfStateData(ref _wnfSWnfShelQuietMomentShellModeChanged, DisableDataBuf, DataBufferSize, IntPtr.Zero, IntPtr.Zero, 0, 0); return result == 0; } } 调用时,最好先调用DisableFoucusMode方法,再调用EnableFocusMode,参考StackOverflow上的说明 ...

2023-07-24 · 2 分钟 · czyt

Zig相关资源

博客 https://www.openmymind.net https://matklad.github.io https://kristoff.it 教程 https://zigbyexample.github.io Zig Cookbook https://ikrima.dev/dev-notes/zig/zig-crash-course/ https://ikrima.dev/dev-notes/zig/zig-metaprogramming/ https://zig.guide https://course.ziglang.cc Introduction to Zig Zig Common Tasks zig资讯 zig news 软件包 https://zig.pm

2023-07-20 · 1 分钟 · czyt

Zig语言快速参考

本文使用AI自动翻译,原文链接 第 0 章 - 入门 欢迎 Zig 是一种通用编程语言和工具链,用于维护健壮、最佳和可重用的软件。 警告:最新的主要版本是 0.10.1 - Zig 仍然是 1.0 之前的版本;仍然不建议在生产中使用,并且您可能会遇到编译器错误。 要遵循本指南,我们假设您已经: 先前的编程经验 对低级编程概念的一些理解 了解 C、C++、Rust、Go、Pascal 或类似语言将有助于遵循本指南。您应该有一个可用的编辑器、终端和互联网连接。本指南是非官方的,与 Zig Software Foundation 无关,旨在从一开始就按顺序阅读。 Installation 本指南假设您使用 Zig 的主版本而不是最新的主要版本,这意味着从网站下载二进制文件或从源代码编译;您的包管理器中的 Zig 版本可能已过时。本指南不支持 Zig 0.10.1。 从以下位置下载并提取 Zig 的预构建主二进制文件: https://ziglang.org/download/ 将 Zig 添加到您的路径 linux, macos, bsd 将 Zig 二进制文件的位置添加到 PATH 环境变量中。对于安装,请添加 export PATH=$PATH:~/zig 或类似于 /etc/profile(系统范围)或 $HOME/.profile。如果这些更改没有立即应用,请从 shell 运行该行。 windows a) 系统范围(admin powershell) [Environment]::SetEnvironmentVariable( "Path", [Environment]::GetEnvironmentVariable("Path", "Machine") + ";C:\your-path\zig-windows-x86_64-your-version", "Machine" ) b) 用户级别(powershell) [Environment]::SetEnvironmentVariable( "Path", [Environment]::GetEnvironmentVariable("Path", "User") + ";C:\your-path\zig-windows-x86_64-your-version", "User" ) 关闭您的终端并创建一个新终端。 ...

2023-07-19 · 42 分钟 · czyt

Golang 防火墙编程

非编程方式 Windows 使用netsh方式进行防火墙规则的维护 Linux 编程方式 Windows Tailscale开发了一个应用WFP的库inet.af/wf 。参考参考链接。在tailscale中的封装代码如下(源链接 ): // Copyright (c) Tailscale Inc & AUTHORS // SPDX-License-Identifier: BSD-3-Clause //go:build windows package wf import ( "fmt" "net/netip" "os" "golang.org/x/sys/windows" "inet.af/wf" "tailscale.com/net/netaddr" ) // Known addresses. var ( linkLocalRange = netip.MustParsePrefix("ff80::/10") linkLocalDHCPMulticast = netip.MustParseAddr("ff02::1:2") siteLocalDHCPMulticast = netip.MustParseAddr("ff05::1:3") linkLocalRouterMulticast = netip.MustParseAddr("ff02::2") ) type direction int const ( directionInbound direction = iota directionOutbound directionBoth ) type protocol int const ( protocolV4 protocol = iota protocolV6 protocolAll ) // getLayers returns the wf.LayerIDs where the rules should be added based // on the protocol and direction. func (p protocol) getLayers(d direction) []wf.LayerID { var layers []wf.LayerID if p == protocolAll || p == protocolV4 { if d == directionBoth || d == directionInbound { layers = append(layers, wf.LayerALEAuthRecvAcceptV4) } if d == directionBoth || d == directionOutbound { layers = append(layers, wf.LayerALEAuthConnectV4) } } if p == protocolAll || p == protocolV6 { if d == directionBoth || d == directionInbound { layers = append(layers, wf.LayerALEAuthRecvAcceptV6) } if d == directionBoth || d == directionOutbound { layers = append(layers, wf.LayerALEAuthConnectV6) } } return layers } func ruleName(action wf.Action, l wf.LayerID, name string) string { switch l { case wf.LayerALEAuthConnectV4: return fmt.Sprintf("%s outbound %s (IPv4)", action, name) case wf.LayerALEAuthConnectV6: return fmt.Sprintf("%s outbound %s (IPv6)", action, name) case wf.LayerALEAuthRecvAcceptV4: return fmt.Sprintf("%s inbound %s (IPv4)", action, name) case wf.LayerALEAuthRecvAcceptV6: return fmt.Sprintf("%s inbound %s (IPv6)", action, name) } return "" } // Firewall uses the Windows Filtering Platform to implement a network firewall. type Firewall struct { luid uint64 providerID wf.ProviderID sublayerID wf.SublayerID session *wf.Session permittedRoutes map[netip.Prefix][]*wf.Rule } // New returns a new Firewall for the provided interface ID. func New(luid uint64) (*Firewall, error) { session, err := wf.New(&wf.Options{ Name: "Tailscale firewall", Dynamic: true, }) if err != nil { return nil, err } wguid, err := windows.GenerateGUID() if err != nil { return nil, err } providerID := wf.ProviderID(wguid) if err := session.AddProvider(&wf.Provider{ ID: providerID, Name: "Tailscale provider", }); err != nil { return nil, err } wguid, err = windows.GenerateGUID() if err != nil { return nil, err } sublayerID := wf.SublayerID(wguid) if err := session.AddSublayer(&wf.Sublayer{ ID: sublayerID, Name: "Tailscale permissive and blocking filters", Weight: 0, }); err != nil { return nil, err } f := &Firewall{ luid: luid, session: session, providerID: providerID, sublayerID: sublayerID, permittedRoutes: make(map[netip.Prefix][]*wf.Rule), } if err := f.enable(); err != nil { return nil, err } return f, nil } type weight uint64 const ( weightTailscaleTraffic weight = 15 weightKnownTraffic weight = 12 weightCatchAll weight = 0 ) func (f *Firewall) enable() error { if err := f.permitTailscaleService(weightTailscaleTraffic); err != nil { return fmt.Errorf("permitTailscaleService failed: %w", err) } if err := f.permitTunInterface(weightTailscaleTraffic); err != nil { return fmt.Errorf("permitTunInterface failed: %w", err) } if err := f.permitDNS(weightTailscaleTraffic); err != nil { return fmt.Errorf("permitDNS failed: %w", err) } if err := f.permitLoopback(weightTailscaleTraffic); err != nil { return fmt.Errorf("permitLoopback failed: %w", err) } if err := f.permitDHCPv4(weightKnownTraffic); err != nil { return fmt.Errorf("permitDHCPv4 failed: %w", err) } if err := f.permitDHCPv6(weightKnownTraffic); err != nil { return fmt.Errorf("permitDHCPv6 failed: %w", err) } if err := f.permitNDP(weightKnownTraffic); err != nil { return fmt.Errorf("permitNDP failed: %w", err) } /* TODO: actually evaluate if this does anything and if we need this. It's layer 2; our other rules are layer 3. * In other words, if somebody complains, try enabling it. For now, keep it off. * TODO(maisem): implement this. err = permitHyperV(session, baseObjects, weightKnownTraffic) if err != nil { return wrapErr(err) } */ if err := f.blockAll(weightCatchAll); err != nil { return fmt.Errorf("blockAll failed: %w", err) } return nil } // UpdatedPermittedRoutes adds rules to allow incoming and outgoing connections // from the provided prefixes. It will also remove rules for routes that were // previously added but have been removed. func (f *Firewall) UpdatePermittedRoutes(newRoutes []netip.Prefix) error { var routesToAdd []netip.Prefix routeMap := make(map[netip.Prefix]bool) for _, r := range newRoutes { routeMap[r] = true if _, ok := f.permittedRoutes[r]; !ok { routesToAdd = append(routesToAdd, r) } } var routesToRemove []netip.Prefix for r := range f.permittedRoutes { if !routeMap[r] { routesToRemove = append(routesToRemove, r) } } for _, r := range routesToRemove { for _, rule := range f.permittedRoutes[r] { if err := f.session.DeleteRule(rule.ID); err != nil { return err } } delete(f.permittedRoutes, r) } for _, r := range routesToAdd { conditions := []*wf.Match{ { Field: wf.FieldIPRemoteAddress, Op: wf.MatchTypeEqual, Value: r, }, } var p protocol if r.Addr().Is4() { p = protocolV4 } else { p = protocolV6 } rules, err := f.addRules("local route", weightKnownTraffic, conditions, wf.ActionPermit, p, directionBoth) if err != nil { return err } f.permittedRoutes[r] = rules } return nil } func (f *Firewall) newRule(name string, w weight, layer wf.LayerID, conditions []*wf.Match, action wf.Action) (*wf.Rule, error) { id, err := windows.GenerateGUID() if err != nil { return nil, err } return &wf.Rule{ Name: ruleName(action, layer, name), ID: wf.RuleID(id), Provider: f.providerID, Sublayer: f.sublayerID, Layer: layer, Weight: uint64(w), Conditions: conditions, Action: action, }, nil } func (f *Firewall) addRules(name string, w weight, conditions []*wf.Match, action wf.Action, p protocol, d direction) ([]*wf.Rule, error) { var rules []*wf.Rule for _, l := range p.getLayers(d) { r, err := f.newRule(name, w, l, conditions, action) if err != nil { return nil, err } if err := f.session.AddRule(r); err != nil { return nil, err } rules = append(rules, r) } return rules, nil } func (f *Firewall) blockAll(w weight) error { _, err := f.addRules("all", w, nil, wf.ActionBlock, protocolAll, directionBoth) return err } func (f *Firewall) permitNDP(w weight) error { // These are aliased according to: // https://social.msdn.microsoft.com/Forums/azure/en-US/eb2aa3cd-5f1c-4461-af86-61e7d43ccc23/filtering-icmp-by-type-code?forum=wfp fieldICMPType := wf.FieldIPLocalPort fieldICMPCode := wf.FieldIPRemotePort var icmpConditions = func(t, c uint16, remoteAddress any) []*wf.Match { conditions := []*wf.Match{ { Field: wf.FieldIPProtocol, Op: wf.MatchTypeEqual, Value: wf.IPProtoICMPV6, }, { Field: fieldICMPType, Op: wf.MatchTypeEqual, Value: t, }, { Field: fieldICMPCode, Op: wf.MatchTypeEqual, Value: c, }, } if remoteAddress != nil { conditions = append(conditions, &wf.Match{ Field: wf.FieldIPRemoteAddress, Op: wf.MatchTypeEqual, Value: linkLocalRouterMulticast, }) } return conditions } /* TODO: actually handle the hop limit somehow! The rules should vaguely be: * - icmpv6 133: must be outgoing, dst must be FF02::2/128, hop limit must be 255 * - icmpv6 134: must be incoming, src must be FE80::/10, hop limit must be 255 * - icmpv6 135: either incoming or outgoing, hop limit must be 255 * - icmpv6 136: either incoming or outgoing, hop limit must be 255 * - icmpv6 137: must be incoming, src must be FE80::/10, hop limit must be 255 */ // // Router Solicitation Message // ICMP type 133, code 0. Outgoing. // conditions := icmpConditions(133, 0, linkLocalRouterMulticast) if _, err := f.addRules("NDP type 133", w, conditions, wf.ActionPermit, protocolV6, directionOutbound); err != nil { return err } // // Router Advertisement Message // ICMP type 134, code 0. Incoming. // conditions = icmpConditions(134, 0, linkLocalRange) if _, err := f.addRules("NDP type 134", w, conditions, wf.ActionPermit, protocolV6, directionInbound); err != nil { return err } // // Neighbor Solicitation Message // ICMP type 135, code 0. Bi-directional. // conditions = icmpConditions(135, 0, nil) if _, err := f.addRules("NDP type 135", w, conditions, wf.ActionPermit, protocolV6, directionBoth); err != nil { return err } // // Neighbor Advertisement Message // ICMP type 136, code 0. Bi-directional. // conditions = icmpConditions(136, 0, nil) if _, err := f.addRules("NDP type 136", w, conditions, wf.ActionPermit, protocolV6, directionBoth); err != nil { return err } // // Redirect Message // ICMP type 137, code 0. Incoming. // conditions = icmpConditions(137, 0, linkLocalRange) if _, err := f.addRules("NDP type 137", w, conditions, wf.ActionPermit, protocolV6, directionInbound); err != nil { return err } return nil } func (f *Firewall) permitDHCPv6(w weight) error { var dhcpConditions = func(remoteAddrs ...any) []*wf.Match { conditions := []*wf.Match{ { Field: wf.FieldIPProtocol, Op: wf.MatchTypeEqual, Value: wf.IPProtoUDP, }, { Field: wf.FieldIPLocalAddress, Op: wf.MatchTypeEqual, Value: linkLocalRange, }, { Field: wf.FieldIPLocalPort, Op: wf.MatchTypeEqual, Value: uint16(546), }, { Field: wf.FieldIPRemotePort, Op: wf.MatchTypeEqual, Value: uint16(547), }, } for _, a := range remoteAddrs { conditions = append(conditions, &wf.Match{ Field: wf.FieldIPRemoteAddress, Op: wf.MatchTypeEqual, Value: a, }) } return conditions } conditions := dhcpConditions(linkLocalDHCPMulticast, siteLocalDHCPMulticast) if _, err := f.addRules("DHCP request", w, conditions, wf.ActionPermit, protocolV6, directionOutbound); err != nil { return err } conditions = dhcpConditions(linkLocalRange) if _, err := f.addRules("DHCP response", w, conditions, wf.ActionPermit, protocolV6, directionInbound); err != nil { return err } return nil } func (f *Firewall) permitDHCPv4(w weight) error { var dhcpConditions = func(remoteAddrs ...any) []*wf.Match { conditions := []*wf.Match{ { Field: wf.FieldIPProtocol, Op: wf.MatchTypeEqual, Value: wf.IPProtoUDP, }, { Field: wf.FieldIPLocalPort, Op: wf.MatchTypeEqual, Value: uint16(68), }, { Field: wf.FieldIPRemotePort, Op: wf.MatchTypeEqual, Value: uint16(67), }, } for _, a := range remoteAddrs { conditions = append(conditions, &wf.Match{ Field: wf.FieldIPRemoteAddress, Op: wf.MatchTypeEqual, Value: a, }) } return conditions } conditions := dhcpConditions(netaddr.IPv4(255, 255, 255, 255)) if _, err := f.addRules("DHCP request", w, conditions, wf.ActionPermit, protocolV4, directionOutbound); err != nil { return err } conditions = dhcpConditions() if _, err := f.addRules("DHCP response", w, conditions, wf.ActionPermit, protocolV4, directionInbound); err != nil { return err } return nil } func (f *Firewall) permitTunInterface(w weight) error { condition := []*wf.Match{ { Field: wf.FieldIPLocalInterface, Op: wf.MatchTypeEqual, Value: f.luid, }, } _, err := f.addRules("on TUN", w, condition, wf.ActionPermit, protocolAll, directionBoth) return err } func (f *Firewall) permitLoopback(w weight) error { condition := []*wf.Match{ { Field: wf.FieldFlags, Op: wf.MatchTypeFlagsAllSet, Value: wf.ConditionFlagIsLoopback, }, } _, err := f.addRules("on loopback", w, condition, wf.ActionPermit, protocolAll, directionBoth) return err } func (f *Firewall) permitDNS(w weight) error { conditions := []*wf.Match{ { Field: wf.FieldIPRemotePort, Op: wf.MatchTypeEqual, Value: uint16(53), }, // Repeat the condition type for logical OR. { Field: wf.FieldIPProtocol, Op: wf.MatchTypeEqual, Value: wf.IPProtoUDP, }, { Field: wf.FieldIPProtocol, Op: wf.MatchTypeEqual, Value: wf.IPProtoTCP, }, } _, err := f.addRules("DNS", w, conditions, wf.ActionPermit, protocolAll, directionBoth) return err } func (f *Firewall) permitTailscaleService(w weight) error { currentFile, err := os.Executable() if err != nil { return err } appID, err := wf.AppID(currentFile) if err != nil { return fmt.Errorf("could not get app id for %q: %w", currentFile, err) } conditions := []*wf.Match{ { Field: wf.FieldALEAppID, Op: wf.MatchTypeEqual, Value: appID, }, } _, err = f.addRules("unrestricted traffic for Tailscale service", w, conditions, wf.ActionPermit, protocolAll, directionBoth) return err } Linux Tailscale的Linux版本实现 https://github.com/tailscale/tailscale/blob/main/util/linuxfw/linuxfw.go ...

2023-07-03 · 8 分钟 · czyt

Nginx使用备忘

安装和更新 安装 以ArchLinux为例 yay -S nginx 生成的systemctl单元如下 [Unit] Description=A high performance web server and a reverse proxy server After=network.target network-online.target nss-lookup.target [Service] Type=forking PIDFile=/run/nginx.pid PrivateDevices=yes SyslogLevel=err ExecStart=/usr/bin/nginx -g 'pid /run/nginx.pid; error_log stderr;' ExecReload=/usr/bin/nginx -s reload KillMode=mixed [Install] WantedBy=multi-user.target 更新 查看现有Nginx的编译参数 ➜ ~ nginx -V nginx version: nginx/1.22.1 built with OpenSSL 3.0.7 1 Nov 2022 (running with OpenSSL 3.0.8 7 Feb 2023) TLS SNI support enabled configure arguments: --prefix=/etc/nginx --conf-path=/etc/nginx/nginx.conf --sbin-path=/usr/bin/nginx --pid-path=/run/nginx.pid --lock-path=/run/lock/nginx.lock --user=http --group=http --http-log-path=/var/log/nginx/access.log --error-log-path=stderr --http-client-body-temp-path=/var/lib/nginx/client-body --http-proxy-temp-path=/var/lib/nginx/proxy --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-cc-opt='-march=armv8-a -O2 -pipe -fstack-protector-strong -fno-plt -fexceptions -Wp,-D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -fstack-clash-protection -fPIC' --with-ld-opt=-Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now --with-compat --with-debug --with-file-aio --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_degradation_module --with-http_flv_module --with-http_geoip_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-pcre-jit --with-stream --with-stream_geoip_module --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-threads 下载最新的nginx源码 wget https://nginx.org/download/nginx-1.25.1.tar.gz 然后解压。切换到configure所在目录,并使用上面的参数编译nginx ...

2023-06-21 · 2 分钟 · czyt

初学Flutter时我遇到的问题汇总

这些是我学习Flutter过程中遇到的问题列表 项目问题 Android Studio丢失Image Asset新建项 这样会在新的界面打开IDE,等同步完成,然后就有新建项了。 调试 Flutter编辑时,没有色板预览 需要设置Java运行环境,设置好以后,就可以用了。 Debug条件运行 需要引入flutter/foundation.dart然后,使用kDebugMode进行判断即可。 import 'package:flutter/foundation.dart'; if (kDebugMode) { print(" changed $v"); } 隐藏Debug 条幅 在代码的theme入口代码添加debugShowCheckedModeBanner: false,,完整代码如下: class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), debugShowCheckedModeBanner: false, home: const MyHomePage(title: 'Flutter Demo Home Page'), ); } } AndroidStudio可以显示设备但是Flutter的设备选择没有设备 先检查Android SDK PS C:\Windows\system32> flutter doctor --android-licenses Flutter assets will be downloaded from https://storage.flutter-io.cn. Make sure you trust this source! Unable to locate Android SDK. 然后设置Android SDK路径 ...

2023-05-25 · 2 分钟 · czyt