├── .github └── workflows │ └── main.yml ├── LICENSE ├── README.md ├── egress-ip-ranges.etag ├── egress-ip-ranges.mmdb ├── go.mod ├── go.sum └── main.go /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Go CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - main.go 9 | - go.* 10 | - .github/workflows/** 11 | schedule: 12 | - cron: 10 5 * * * 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - name: Checkout repository 20 | uses: actions/checkout@v3 21 | 22 | - name: Set up Go 23 | uses: actions/setup-go@v3 24 | with: 25 | go-version: '1.22' 26 | 27 | - name: Compile and run main.go 28 | run: | 29 | go run . 30 | 31 | - name: Commit generated files 32 | run: | 33 | git config --global user.name 'github-actions[bot]' 34 | git config --global user.email 'github-actions[bot]@users.noreply.github.com' 35 | git add -u 36 | git diff-index --quiet HEAD || git commit -a -m "[auto] Update generated files" 37 | - name: Push changes 38 | uses: ad-m/github-push-action@master 39 | with: 40 | github_token: ${{ secrets.GITHUB_TOKEN }} 41 | branch: main -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 NextDNS 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # iCloud Private Relay Egress IP Ranges MMDB 3 | 4 | ![iCloud Private Relay](https://support.apple.com/library/content/dam/edam/applecare/images/en_US/icloud/icloud-private-relay-how-private-relay-works-path-through-relays.png) 5 | 6 | This project provides an auto-generated iCloud Private Relay egress IP ranges in MMDB format built from the [official feed](https://mask-api.icloud.com/egress-ip-ranges.csv) provided by Apple. 7 | 8 | The source feed is checked daily for updates, and a new version is automatically generated in case of any changes. 9 | -------------------------------------------------------------------------------- /egress-ip-ranges.etag: -------------------------------------------------------------------------------- 1 | "6833cf0c-b982fd" -------------------------------------------------------------------------------- /egress-ip-ranges.mmdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nextdns/icloud-private-relay-mmdb/f9106051c0499797f3b6693d85ff582c0f2db71b/egress-ip-ranges.mmdb -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/nextdns/icloud-private-relay-mmdb 2 | 3 | go 1.22.4 4 | 5 | require ( 6 | github.com/maxmind/mmdbwriter v1.0.0 7 | github.com/oschwald/maxminddb-golang v1.13.1 // indirect 8 | ) 9 | 10 | require ( 11 | go4.org/netipx v0.0.0-20220812043211-3cc044ffd68d // indirect 12 | golang.org/x/sys v0.21.0 // indirect 13 | ) 14 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/maxmind/mmdbwriter v1.0.0 h1:bieL4P6yaYaHvbtLSwnKtEvScUKKD6jcKaLiTM3WSMw= 4 | github.com/maxmind/mmdbwriter v1.0.0/go.mod h1:noBMCUtyN5PUQ4H8ikkOvGSHhzhLok51fON2hcrpKj8= 5 | github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE= 6 | github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8= 7 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 8 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 9 | github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= 10 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 11 | go4.org/netipx v0.0.0-20220812043211-3cc044ffd68d h1:ggxwEf5eu0l8v+87VhX1czFh8zJul3hK16Gmruxn7hw= 12 | go4.org/netipx v0.0.0-20220812043211-3cc044ffd68d/go.mod h1:tgPU4N2u9RByaTN3NC2p9xOzyFpte4jYwsIIRF7XlSc= 13 | golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= 14 | golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 15 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 16 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 17 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/csv" 6 | "log" 7 | "net" 8 | "net/http" 9 | "os" 10 | 11 | "github.com/maxmind/mmdbwriter" 12 | "github.com/maxmind/mmdbwriter/mmdbtype" 13 | ) 14 | 15 | const egressRanges = "https://mask-api.icloud.com/egress-ip-ranges.csv" 16 | const etagFilename = "egress-ip-ranges.etag" 17 | const outputFilename = "egress-ip-ranges.mmdb" 18 | 19 | func main() { 20 | resp, err := http.Get(egressRanges) 21 | if err != nil { 22 | log.Fatalf("Failed to download file: %v", err) 23 | } 24 | defer resp.Body.Close() 25 | 26 | previousETag, _ := os.ReadFile(etagFilename) 27 | currentEtag := []byte(resp.Header.Get("ETag")) 28 | if bytes.Equal(currentEtag, previousETag) { 29 | log.Println("No changes in the egress IP ranges") 30 | return 31 | } 32 | 33 | reader := csv.NewReader(resp.Body) 34 | records, err := reader.ReadAll() 35 | if err != nil { 36 | log.Fatalf("Failed to read CSV file: %v", err) 37 | } 38 | 39 | writer, err := mmdbwriter.New(mmdbwriter.Options{ 40 | DatabaseType: "GeoIP2-Country", 41 | RecordSize: 24, 42 | }) 43 | if err != nil { 44 | log.Fatalf("Failed to create MMDB writer: %v", err) 45 | } 46 | 47 | // Insert records into the MMDB writer 48 | for _, record := range records { 49 | _, ipNet, err := net.ParseCIDR(record[0]) 50 | if err != nil { 51 | log.Fatalf("Failed to parse CIDR: %v", err) 52 | } 53 | 54 | data := mmdbtype.Map{ 55 | "country": mmdbtype.Map{ 56 | "iso_code": mmdbtype.String(record[1]), 57 | }, 58 | } 59 | 60 | err = writer.Insert(ipNet, data) 61 | if err != nil { 62 | log.Fatalf("Failed to insert record into MMDB: %v", err) 63 | } 64 | } 65 | 66 | // Write the MMDB file 67 | mmdbFile, err := os.Create(outputFilename) 68 | if err != nil { 69 | log.Fatalf("Failed to create MMDB file: %v", err) 70 | } 71 | defer mmdbFile.Close() 72 | 73 | if _, err = writer.WriteTo(mmdbFile); err != nil { 74 | log.Fatalf("Failed to write MMDB file: %v", err) 75 | } 76 | 77 | if err = os.WriteFile(etagFilename, currentEtag, 0644); err != nil { 78 | log.Fatalf("Failed to write etag file: %v", err) 79 | } 80 | } 81 | --------------------------------------------------------------------------------