// Package dnssec implements a plugin that signs responses on-the-fly using // NSEC black lies. package dnssec import ( "time" "github.com/coredns/coredns/plugin" "github.com/coredns/coredns/plugin/pkg/cache" "github.com/coredns/coredns/plugin/pkg/response" "github.com/coredns/coredns/plugin/pkg/singleflight" "github.com/coredns/coredns/request" "github.com/miekg/dns" ) // Dnssec signs the reply on-the-fly. type Dnssec struct { Next plugin.Handler zones []string keys []*DNSKEY splitkeys bool inflight *singleflight.Group cache *cache.Cache } // New returns a new Dnssec. func New(zones []string, keys []*DNSKEY, splitkeys bool, next plugin.Handler, c *cache.Cache) Dnssec { return Dnssec{Next: next, zones: zones, keys: keys, splitkeys: splitkeys, cache: c, inflight: new(singleflight.Group), } } // Sign signs the message in state. it takes care of negative or nodata responses. It // uses NSEC black lies for authenticated denial of existence. For delegations it // will insert DS records and sign those. // Signatures will be cached for a short while. By default we sign for 8 days, // starting 3 hours ago. func (d Dnssec) Sign(state request.Request, now time.Time, server string) *dns.Msg { req := state.Req incep, expir := incepExpir(now) mt, _ := response.Typify(req, time.Now().UTC()) // TODO(miek): need opt record here? if mt == response.Delegation { return req } if mt == response.NameError || mt == response.NoData { if req.Ns[0].Header().Rrtype != dns.TypeSOA || len(req.Ns) > 1 { return req } ttl := req.Ns[0].Header().Ttl if sigs, err := d.sign(req.Ns, state.Zone, ttl, incep, expir, server); err == nil { req.Ns = append(req.Ns, sigs...) } if sigs, err := d.nsec(state, mt, ttl, incep, expir, server); err == nil { req.Ns = append(req.Ns, sigs...) } if len(req.Ns) > 1 { // actually added nsec and sigs, reset the rcode req.Rcode = dns.RcodeSuccess } return req } for _, r := range rrSets(req.Answer) { ttl := r[0].Header().Ttl if sigs, err := d.sign(r, state.Zone, ttl, incep, expir, server); err == nil { req.Answer = append(req.Answer, sigs...) } } for _, r := range rrSets(req.Ns) { ttl := r[0].Header().Ttl if sigs, err := d.sign(r, state.Zone, ttl, incep, expir, server); err == nil { req.Ns = append(req.Ns, sigs...) } } for _, r := range rrSets(req.Extra) { ttl := r[0].Header().Ttl if sigs, err := d.sign(r, state.Zone, ttl, incep, expir, server); err == nil { req.Extra = append(req.Extra, sigs...) } } return req } func (d Dnssec) sign(rrs []dns.RR, signerName string, ttl, incep, expir uint32, server string) ([]dns.RR, error) { k := hash(rrs) sgs, ok := d.get(k, server) if ok { return sgs, nil } sigs, err := d.inflight.Do(k, func() (interface{}, error) { var sigs []dns.RR for _, k := range d.keys { if d.splitkeys { if len(rrs) > 0 && rrs[0].Header().Rrtype == dns.TypeDNSKEY { // We are signing a DNSKEY RRSet. With split keys, we need to use a KSK here. if !k.isKSK() { continue } } else { // For non-DNSKEY RRSets, we want to use a ZSK. if !k.isZSK() { continue } } } sig := k.newRRSIG(signerName, ttl, incep, expir) if e := sig.Sign(k.s, rrs); e != nil { return sigs, e } sigs = append(sigs, sig) } d.set(k, sigs) return sigs, nil }) return sigs.([]dns.RR), err } func (d Dnssec) set(key uint64, sigs []dns.RR) { d.cache.Add(key, sigs) } func (d Dnssec) get(key uint64, server string) ([]dns.RR, bool) { if s, ok := d.cache.Get(key); ok { // we sign for 8 days, check if a signature in the cache reached 3/4 of that is75 := time.Now().UTC().Add(twoDays) for _, rr := range s.([]dns.RR) { if !rr.(*dns.RRSIG).ValidityPeriod(is75) { cacheMisses.WithLabelValues(server).Inc() return nil, false } } cacheHits.WithLabelValues(server).Inc() return s.([]dns.RR), true } cacheMisses.WithLabelValues(server).Inc() return nil, false } func incepExpir(now time.Time) (uint32, uint32) { incep := uint32(now.Add(-3 * time.Hour).Unix()) // -(2+1) hours, be sure to catch daylight saving time and such expir := uint32(now.Add(eightDays).Unix()) // sign for 8 days return incep, expir } const ( eightDays = 8 * 24 * time.Hour twoDays = 2 * 24 * time.Hour defaultCap = 10000 // default capacity of the cache. ) >examples/integration Unnamed repository; edit this file 'description' to name the repository.
aboutsummaryrefslogtreecommitdiff
path: root/examples/framework-alpine/public (unfollow)
AgeCommit message (Expand)AuthorFilesLines
2022-04-26Update `@proload/core` (#3211)Gravatar Nate Moore 3-6/+6
2022-04-26Revert "fix: replace serialize-javascript & random-bytes with custom internal...Gravatar Nate Moore 7-565/+215
2022-04-26[ci] formatGravatar okikio 2-271/+315
2022-04-26fix: replace serialize-javascript & random-bytes with custom internal modulesGravatar Okiki 7-215/+521
2022-04-26[ci] release (#3182)create-astro@0.10.0astro@1.0.0-beta.18@astrojs/vercel@0.1.4@astrojs/tailwind@0.2.1@astrojs/svelte@0.1.2@astrojs/netlify@0.3.3Gravatar github-actions[bot] 54-146/+130
2022-04-26[ci] formatGravatar matthewp 1-1/+1
2022-04-26fix(vercel): `trailingSlash` fix for non-html pages (#3185)Gravatar Juan Martín Seery 2-29/+42
2022-04-26Prevent watcher from running during the build (#3207)Gravatar Matthew Phillips 2-0/+9
2022-04-26Fix lockfile (#3210)Gravatar Juan Martín Seery 1-6/+0
2022-04-26Add missing is:raw in AstroBuiltinAttributes (#3209)Gravatar Erika 2-0/+6
2022-04-26Feat: support `astro add` without npm installing (#3183)Gravatar Ben Holmes 6-30/+49
2022-04-26Add Astro attributes to svg elements (#3205)Gravatar Erika 2-1/+9
2022-04-26[ci] formatGravatar bholmesdev 2-9/+9
2022-04-26Feat: `create astro` add install step (#3190)Gravatar Ben Holmes 7-162/+299
2022-04-26[ci] collect statsGravatar FredKSchott 1-0/+1
2022-04-25fix(markdown): file.url fixes (#3198)Gravatar Juan Martín Seery 11-10/+149
2022-04-25[ci] collect statsGravatar FredKSchott 1-0/+1
2022-04-24add vite to licenseGravatar Fred K. Schott 2-24/+29
2022-04-24feat(markdown): Improved types (#3191)Gravatar Juan Martín Seery 3-6/+47
2022-04-24[ci] collect statsGravatar FredKSchott 1-0/+1
2022-04-23[ci] collect statsGravatar FredKSchott 1-0/+1